Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore(deps): update dependency drizzle-orm to ^0.33.0 #28

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

renovate[bot]
Copy link
Contributor

@renovate renovate bot commented Nov 9, 2023

This PR contains the following updates:

Package Change Age Adoption Passing Confidence
drizzle-orm (source) ^0.28.6 -> ^0.33.0 age adoption passing confidence

Release Notes

drizzle-team/drizzle-orm (drizzle-orm)

v0.33.0

Compare Source

Breaking changes (for some of postgres.js users)

Bugs fixed for this breaking change

As we are doing with other drivers, we've changed the behavior of PostgreSQL-JS to pass raw JSON values, the same as you see them in the database. So if you are using the PostgreSQL-JS driver and passing data to Drizzle elsewhere, please check the new behavior of the client after it is passed to Drizzle.

We will update it to ensure it does not override driver behaviors, but this will be done as a complex task for everything in Drizzle in other releases

If you were using postgres-js with jsonb fields, you might have seen stringified objects in your database, while drizzle insert and select operations were working as expected.

You need to convert those fields from strings to actual JSON objects. To do this, you can use the following query to update your database:

if you are using jsonb:

update table_name
set jsonb_column = (jsonb_column #>> '{}')::jsonb;

if you are using json:

update table_name
set json_column = (json_column #>> '{}')::json;

We've tested it in several cases, and it worked well, but only if all stringified objects are arrays or objects. If you have primitives like strings, numbers, booleans, etc., you can use this query to update all the fields

if you are using jsonb:

UPDATE table_name
SET jsonb_column = CASE
    -- Convert to JSONB if it is a valid JSON object or array
    WHEN jsonb_column #>> '{}' LIKE '{%' OR jsonb_column #>> '{}' LIKE '[%' THEN
        (jsonb_column #>> '{}')::jsonb
    ELSE
        jsonb_column
END
WHERE
    jsonb_column IS NOT NULL;

if you are using json:

UPDATE table_name
SET json_column = CASE
    -- Convert to JSON if it is a valid JSON object or array
    WHEN json_column #>> '{}' LIKE '{%' OR json_column #>> '{}' LIKE '[%' THEN
        (json_column #>> '{}')::json
    ELSE
        json_column
END
WHERE json_column IS NOT NULL;

If nothing works for you and you are blocked, please reach out to me @​AndriiSherman. I will try to help you!

Bug Fixes

v0.32.2

Compare Source

  • Fix AWS Data API type hints bugs in RQB
  • Fix set transactions in MySQL bug - thanks @​roguesherlock
  • Add forwaring dependencies within useLiveQuery, fixes #​2651 - thanks @​anstapol
  • Export additional types from SQLite package, like AnySQLiteUpdate - thanks @​veloii

v0.32.1

Compare Source

  • Fix typings for indexes and allow creating indexes on 3+ columns mixing columns and expressions - thanks @​lbguilherme!
  • Added support for "limit 0" in all dialects - closes #​2011 - thanks @​sillvva!
  • Make inArray and notInArray accept empty list, closes #​1295 - thanks @​RemiPeruto!
  • fix typo in lt typedoc - thanks @​dalechyn!
  • fix wrong example in README.md - thanks @​7flash!

v0.32.0

Compare Source

Release notes for [email protected] and [email protected]

It's not mandatory to upgrade both packages, but if you want to use the new features in both queries and migrations, you will need to upgrade both packages

New Features

🎉 MySQL $returningId() function

MySQL itself doesn't have native support for RETURNING after using INSERT. There is only one way to do it for primary keys with autoincrement (or serial) types, where you can access insertId and affectedRows fields. We've prepared an automatic way for you to handle such cases with Drizzle and automatically receive all inserted IDs as separate objects

import { boolean, int, text, mysqlTable } from 'drizzle-orm/mysql-core';

const usersTable = mysqlTable('users', {
  id: int('id').primaryKey(),
  name: text('name').notNull(),
  verified: boolean('verified').notNull().default(false),
});

const result = await db.insert(usersTable).values([{ name: 'John' }, { name: 'John1' }]).$returningId();
//    ^? { id: number }[]

Also with Drizzle, you can specify a primary key with $default function that will generate custom primary keys at runtime. We will also return those generated keys for you in the $returningId() call

import { varchar, text, mysqlTable } from 'drizzle-orm/mysql-core';
import { createId } from '@​paralleldrive/cuid2';

const usersTableDefFn = mysqlTable('users_default_fn', {
  customId: varchar('id', { length: 256 }).primaryKey().$defaultFn(createId),
  name: text('name').notNull(),
});

const result = await db.insert(usersTableDefFn).values([{ name: 'John' }, { name: 'John1' }]).$returningId();
//  ^? { customId: string }[]

If there is no primary keys -> type will be {}[] for such queries

🎉 PostgreSQL Sequences

You can now specify sequences in Postgres within any schema you need and define all the available properties

Example
import { pgSchema, pgSequence } from "drizzle-orm/pg-core";

// No params specified
export const customSequence = pgSequence("name");

// Sequence with params
export const customSequence = pgSequence("name", {
      startWith: 100,
      maxValue: 10000,
      minValue: 100,
      cycle: true,
      cache: 10,
      increment: 2
});

// Sequence in custom schema
export const customSchema = pgSchema('custom_schema');

export const customSequence = customSchema.sequence("name");
🎉 PostgreSQL Identity Columns

Source: As mentioned, the serial type in Postgres is outdated and should be deprecated. Ideally, you should not use it. Identity columns are the recommended way to specify sequences in your schema, which is why we are introducing the identity columns feature

Example
import { pgTable, integer, text } from 'drizzle-orm/pg-core' 

export const ingredients = pgTable("ingredients", {
  id: integer("id").primaryKey().generatedAlwaysAsIdentity({ startWith: 1000 }),
  name: text("name").notNull(),
  description: text("description"),
});

You can specify all properties available for sequences in the .generatedAlwaysAsIdentity() function. Additionally, you can specify custom names for these sequences

PostgreSQL docs reference.

🎉 PostgreSQL Generated Columns

You can now specify generated columns on any column supported by PostgreSQL to use with generated columns

Example with generated column for tsvector

Note: we will add tsVector column type before latest release

import { SQL, sql } from "drizzle-orm";
import { customType, index, integer, pgTable, text } from "drizzle-orm/pg-core";

const tsVector = customType<{ data: string }>({
  dataType() {
    return "tsvector";
  },
});

export const test = pgTable(
  "test",
  {
    id: integer("id").primaryKey().generatedAlwaysAsIdentity(),
    content: text("content"),
    contentSearch: tsVector("content_search", {
      dimensions: 3,
    }).generatedAlwaysAs(
      (): SQL => sql`to_tsvector('english', ${test.content})`
    ),
  },
  (t) => ({
    idx: index("idx_content_search").using("gin", t.contentSearch),
  })
);

In case you don't need to reference any columns from your table, you can use just sql template or a string

export const users = pgTable("users", {
  id: integer("id"),
  name: text("name"),
  generatedName: text("gen_name").generatedAlwaysAs(sql`hello world!`),
  generatedName1: text("gen_name1").generatedAlwaysAs("hello world!"),
}),
🎉 MySQL Generated Columns

You can now specify generated columns on any column supported by MySQL to use with generated columns

You can specify both stored and virtual options, for more info you can check MySQL docs

Also MySQL has a few limitation for such columns usage, which is described here

Drizzle Kit will also have limitations for push command:

  1. You can't change the generated constraint expression and type using push. Drizzle-kit will ignore this change. To make it work, you would need to drop the column, push, and then add a column with a new expression. This was done due to the complex mapping from the database side, where the schema expression will be modified on the database side and, on introspection, we will get a different string. We can't be sure if you changed this expression or if it was changed and formatted by the database. As long as these are generated columns and push is mostly used for prototyping on a local database, it should be fast to drop and create generated columns. Since these columns are generated, all the data will be restored

  2. generate should have no limitations

Example
export const users = mysqlTable("users", {
  id: int("id"),
  id2: int("id2"),
  name: text("name"),
  generatedName: text("gen_name").generatedAlwaysAs(
    (): SQL => sql`${schema2.users.name} || 'hello'`,
    { mode: "stored" }
  ),
  generatedName1: text("gen_name1").generatedAlwaysAs(
    (): SQL => sql`${schema2.users.name} || 'hello'`,
    { mode: "virtual" }
  ),
}),

In case you don't need to reference any columns from your table, you can use just sql template or a string in .generatedAlwaysAs()

🎉 SQLite Generated Columns

You can now specify generated columns on any column supported by SQLite to use with generated columns

You can specify both stored and virtual options, for more info you can check SQLite docs

Also SQLite has a few limitation for such columns usage, which is described here

Drizzle Kit will also have limitations for push and generate command:

  1. You can't change the generated constraint expression with the stored type in an existing table. You would need to delete this table and create it again. This is due to SQLite limitations for such actions. We will handle this case in future releases (it will involve the creation of a new table with data migration).

  2. You can't add a stored generated expression to an existing column for the same reason as above. However, you can add a virtual expression to an existing column.

  3. You can't change a stored generated expression in an existing column for the same reason as above. However, you can change a virtual expression.

  4. You can't change the generated constraint type from virtual to stored for the same reason as above. However, you can change from stored to virtual.

New Drizzle Kit features

🎉 Migrations support for all the new orm features

PostgreSQL sequences, identity columns and generated columns for all dialects

🎉 New flag --force for drizzle-kit push

You can auto-accept all data-loss statements using the push command. It's only available in CLI parameters. Make sure you always use it if you are fine with running data-loss statements on your database

🎉 New migrations flag prefix

You can now customize migration file prefixes to make the format suitable for your migration tools:

  • index is the default type and will result in 0001_name.sql file names;
  • supabase and timestamp are equal and will result in 20240627123900_name.sql file names;
  • unix will result in unix seconds prefixes 1719481298_name.sql file names;
  • none will omit the prefix completely;
Example: Supabase migrations format
import { defineConfig } from "drizzle-kit";

export default defineConfig({
  dialect: "postgresql",
  migrations: {
    prefix: 'supabase'
  }
});

v0.31.4

Compare Source

  • Mark prisma clients package as optional - thanks @​Cherry

v0.31.3

Compare Source

Bug fixed
  • 🛠️ Fixed RQB behavior for tables with same names in different schemas
  • 🛠️ Fixed [BUG]: Mismatched type hints when using RDS Data API - #​2097
New Prisma-Drizzle extension
import { PrismaClient } from '@&#8203;prisma/client';
import { drizzle } from 'drizzle-orm/prisma/pg';
import { User } from './drizzle';

const prisma = new PrismaClient().$extends(drizzle());
const users = await prisma.$drizzle.select().from(User);

For more info, check docs: https://orm.drizzle.team/docs/prisma

v0.31.2

Compare Source

  • 🎉 Added support for TiDB Cloud Serverless driver:

    import { connect } from '@&#8203;tidbcloud/serverless';
    import { drizzle } from 'drizzle-orm/tidb-serverless';
    
    const client = connect({ url: '...' });
    const db = drizzle(client);
    await db.select().from(...);

v0.31.1

Compare Source

New Features

Live Queries 🎉

For a full explanation about Drizzle + Expo welcome to discussions

As of v0.31.1 Drizzle ORM now has native support for Expo SQLite Live Queries!
We've implemented a native useLiveQuery React Hook which observes necessary database changes and automatically re-runs database queries. It works with both SQL-like and Drizzle Queries:

import { useLiveQuery, drizzle } from 'drizzle-orm/expo-sqlite';
import { openDatabaseSync } from 'expo-sqlite/next';
import { users } from './schema';
import { Text } from 'react-native';

const expo = openDatabaseSync('db.db', { enableChangeListener: true }); // <-- enable change listeners
const db = drizzle(expo);

const App = () => {
  // Re-renders automatically when data changes
  const { data } = useLiveQuery(db.select().from(users));

  // const { data, error, updatedAt } = useLiveQuery(db.query.users.findFirst());
  // const { data, error, updatedAt } = useLiveQuery(db.query.users.findMany());

  return <Text>{JSON.stringify(data)}</Text>;
};

export default App;

We've intentionally not changed the API of ORM itself to stay with conventional React Hook API, so we have useLiveQuery(databaseQuery) as opposed to db.select().from(users).useLive() or db.query.users.useFindMany()

We've also decided to provide data, error and updatedAt fields as a result of hook for concise explicit error handling following practices of React Query and Electric SQL

v0.31.0

Compare Source

Breaking changes

Note: [email protected] can be used with [email protected] or higher. The same applies to Drizzle Kit. If you run a Drizzle Kit command, it will check and prompt you for an upgrade (if needed). You can check for Drizzle Kit updates. below

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!

🎉 New PostgreSQL types: point, line

You can now use point and line from PostgreSQL Geometric Types

Type point has 2 modes for mappings from the database: tuple and xy.

  • tuple will be accepted for insert and mapped on select to a tuple. So, the database Point(1,2) will be typed as [1,2] with drizzle.

  • xy will be accepted for insert and mapped on select to an object with x, y coordinates. So, the database Point(1,2) will be typed as { x: 1, y: 2 } with drizzle

const items = pgTable('items', {
 point: point('point'),
 pointObj: point('point_xy', { mode: 'xy' }),
});

Type line has 2 modes for mappings from the database: tuple and abc.

  • tuple will be accepted for insert and mapped on select to a tuple. So, the database Line{1,2,3} will be typed as [1,2,3] with drizzle.

  • abc will be accepted for insert and mapped on select to an object with a, b, and c constants from the equation Ax + By + C = 0. So, the database Line{1,2,3} will be typed as { a: 1, b: 2, c: 3 } with drizzle.

const items = pgTable('items', {
 line: line('line'),
 lineObj: point('line_abc', { mode: 'abc' }),
});

🎉 Basic "postgis" extension support

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

geometry type from postgis extension:

const items = pgTable('items', {
  geo: geometry('geo', { type: 'point' }),
  geoObj: geometry('geo_obj', { type: 'point', mode: 'xy' }),
  geoSrid: geometry('geo_options', { type: 'point', mode: 'xy', srid: 4000 }),
});

mode
Type geometry has 2 modes for mappings from the database: tuple and xy.

  • tuple will be accepted for insert and mapped on select to a tuple. So, the database geometry will be typed as [1,2] with drizzle.
  • xy will be accepted for insert and mapped on select to an object with x, y coordinates. So, the database geometry will be typed as { x: 1, y: 2 } with drizzle

type

The current release has a predefined type: point, which is the geometry(Point) type in the PostgreSQL PostGIS extension. You can specify any string there if you want to use some other type

Drizzle Kit updates: [email protected]

Release notes here are partially duplicated from [email protected]

New Features

🎉 Support for new types

Drizzle Kit can now handle:

  • point and line from PostgreSQL
  • vector from the PostgreSQL pg_vector extension
  • geometry from the PostgreSQL PostGIS extension
🎉 New param in drizzle.config - extensionsFilters

The PostGIS extension creates a few internal tables in the public schema. This means that if you have a database with the PostGIS extension and use push or introspect, all those tables will be included in diff operations. In this case, you would need to specify tablesFilter, find all tables created by the extension, and list them in this parameter.

We have addressed this issue so that you won't need to take all these steps. Simply specify extensionsFilters with the name of the extension used, and Drizzle will skip all the necessary tables.

Currently, we only support the postgis option, but we plan to add more extensions if they create tables in the public schema.

The postgis option will skip the geography_columns, geometry_columns, and spatial_ref_sys tables

import { defineConfig } from 'drizzle-kit'

export default defaultConfig({
  dialect: "postgresql",
  extensionsFilters: ["postgis"],
})

Improvements

Update zod schemas for database credentials and write tests to all the positive/negative cases
  • support full set of SSL params in kit config, provide types from node:tls connection
import { defineConfig } from 'drizzle-kit'

export default defaultConfig({
  dialect: "postgresql",
  dbCredentials: {
    ssl: true, //"require" | "allow" | "prefer" | "verify-full" | options from node:tls
  }
})
import { defineConfig } from 'drizzle-kit'

export default defaultConfig({
  dialect: "mysql",
  dbCredentials: {
    ssl: "", // string | SslOptions (ssl options from mysql2 package)
  }
})
Normilized SQLite urls for libsql and better-sqlite3 drivers

Those drivers have different file path patterns, and Drizzle Kit will accept both and create a proper file path format for each

Updated MySQL and SQLite index-as-expression behavior

In this release MySQL and SQLite will properly map expressions into SQL query. Expressions won't be escaped in string but columns will be

export const users = sqliteTable(
  'users',
  {
    id: integer('id').primaryKey(),
    email: text('email').notNull(),
  },
  (table) => ({
    emailUniqueIndex: uniqueIndex('emailUniqueIndex').on(sql`lower(${table.email})`),
  }),
);
-- before
CREATE UNIQUE INDEX `emailUniqueIndex` ON `users` (`lower("users"."email")`);

-- now
CREATE UNIQUE INDEX `emailUniqueIndex` ON `users` (lower("email"));

Bug Fixes

  • [BUG]: multiple constraints not added (only the first one is generated) - #​2341
  • Drizzle Studio: Error: Connection terminated unexpectedly - #​435
  • Unable to run sqlite migrations local - #​432
  • error: unknown option '--config' - #​423

How push and generate works for indexes

Limitations
You should specify a name for your index manually if you have an index on at least one expression

Example

index().on(table.id, table.email) // will work well and name will be autogeneretaed
index('my_name').on(table.id, table.email) // will work well

// but

index().on(sql`lower(${table.email})`) // error
index('my_name').on(sql`lower(${table.email})`) // will work well
Push won't generate statements if these fields(list below) were changed in an existing index:
  • expressions inside .on() and .using()
  • .where() statements
  • operator classes .op() on columns

If you are using push workflows and want to change these fields in the index, you would need to:

  • Comment out the index
  • Push
  • Uncomment the index and change those fields
  • Push again

For the generate command, drizzle-kit will be triggered by any changes in the index for any property in the new drizzle indexes API, so there are no limitations here.

v0.30.10

Compare Source

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

v0.30.9

Compare Source

  • 🐛 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

v0.30.8

Compare Source

  • 🎉 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!

v0.30.7

Compare Source

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

v0.30.6

Compare Source

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 '@&#8203;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:

v0.30.5

Compare Source

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!

v0.30.4

Compare Source

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 @&#8203;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

v0.30.3

Compare Source

v0.30.2

Compare Source

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

v0.30.1

Compare Source

New Features

🎉 OP-SQLite driver Support

Usage Example

import { open } from '@&#8203;op-engineering/op-sqlite';
import { drizzle } from 'drizzle-orm/op-sqlite';

const opsqlite = open({
	name: 'myDB',
});
const db = drizzle(opsqlite);

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

For more usage and setup details, please check our op-sqlite docs

Bug fixes
  • Migration hook fixed for Expo driver

v0.30.0

Compare Source

Breaking Changes

The Postgres timestamp mapping has been changed to align all drivers with the same behavior.

❗ We've modified the postgres.js driver instance to always return strings for dates, and then Drizzle will provide you with either strings of mapped dates, depending on the selected mode. The only issue you may encounter is that once you provide the `postgres.js`` driver instance inside Drizzle, the behavior of this object will change for dates, which will always be strings.

We've made this change as a minor release, just as a warning, that:

  • If you were using timestamps and were waiting for a specific response, the behavior will now be changed.
    When mapping to the driver, we will always use .toISOString for both timestamps with timezone and without timezone.

  • If you were using the postgres.js driver outside of Drizzle, all postgres.js clients passed to Drizzle will have mutated behavior for dates. All dates will be strings in the response.

Parsers that were changed for postgres.js.

const transparentParser = (val: any) => val;

// Override postgres.js default date parsers: https://github.com/porsager/postgres/discussions/761
for (const type of ['1184', '1082', '1083', '1114']) {
	client.options.parsers[type as any] = transparentParser;
	client.options.serializers[type as any] = transparentParser;
}

Ideally, as is the case with almost all other drivers, we should have the possibility to mutate mappings on a per-query basis, which means that the driver client won't be mutated. We will be reaching out to the creator of the postgres.js library to inquire about the possibility of specifying per-query mapping interceptors and making this flow even better for all users.

If we've overlooked this capability and it is already available with `postgres.js``, please ping us in our Discord!

A few more references for timestamps without and with timezones can be found in our docs

Bug fixed in this release

Big thanks to @​Angelelz!

  • [BUG]: timestamp with mode string is returned as Date object instead of string - #​806
  • [BUG]: Dates are always dates #​971
  • [BUG]: Inconsistencies when working with timestamps and corresponding datetime objects in javascript. #​1176
  • [BUG]: timestamp columns showing string type, however actually returning a Date object. #​1185
  • [BUG]: Wrong data type for postgres date colum #​1407
  • [BUG]: invalid timestamp conversion when using PostgreSQL with TimeZone set to UTC #​1587
  • [BUG]: Postgres insert into timestamp with time zone removes milliseconds #​1061
  • [BUG]: update timestamp field (using AWS Data API) #​1164
  • [BUG]: Invalid date from relational queries #​895

v0.29.5

Compare Source

New Features

🎉 WITH UPDATE, WITH DELETE, WITH INSERT - thanks @​L-Mario564

You can now use WITH statements with INSERT, UPDATE and DELETE statements

Usage examples

const averageAmount = db.$with('average_amount').as(
	db.select({ value: sql`avg(${orders.amount})`.as('value') }).from(orders),
);
const result = await db
	.with(averageAmount)
	.delete(orders)
	.where(gt(orders.amount, sql`(select * from ${averageAmount})`))
	.returning({
		id: orders.id,
	});

Generated SQL:

with "average_amount" as (select avg("amount") as "value" from "orders") 
delete from "orders" 
where "orders"."amount" > (select * from "average_amount") 
returning "id"

For more examples for all statements, check docs:

🎉 Possibility to specify custom schema and custom name for migrations table - thanks @​g3r4n
  • Custom table for migrations

By default, all information about executed migrations will be stored in the database inside the __drizzle_migrations table,
and for PostgreSQL, inside the drizzle schema. However, you can configure where to store those records.

To add a custom table name for migrations stored inside your database, you should use the migrationsTable option

Usage example

await migrate(db, {
	migrationsFolder: './drizzle',
	migrationsTable: 'my_migrations',
});
  • Custom schema for migrations

Works only with PostgreSQL databases

To add a custom schema name for migrations stored inside your database, you should use the migrationsSchema option

Usage example

await migrate(db, {
	migrationsFolder: './drizzle',
	migrationsSchema: 'custom',
});
🎉 SQLite Proxy bacth and Relational Queries support
  • You can now use .query.findFirst and .query.findMany syntax with sqlite proxy driver

  • SQLite Proxy supports batch requests, the same as it's done for all other drivers. Check full docs

    You will need to specify a specific callback for batch queries and handle requests to proxy server:

import { drizzle } from 'drizzle-orm/sqlite-proxy';

type ResponseType = { rows: any[][] | any[] }[];

const db = drizzle(
	async (sql, params, method) => {
		// single query logic
	},
	// new batch callback
	async (
		queries: {
			sql: string;
			params: any[];
			method: 'all' | 'run' | 'get' | 'values';
		}[],
	) => {
		try {
			const result: ResponseType = await axios.post(
				'http://localhost:3000/batch',
				{ queries },
			);

			return result;
		} catch (e: any) {
			console.error('Error from sqlite proxy server:', e);
			throw e;
		}
	},
);

And then you can use db.batch([]) method, that will proxy all queries

Response from the batch should be an array of raw values (an array within an array), in the same order as they were sent to the proxy server

v0.29.4

Compare Source

New Features
🎉 Neon HTTP Batch

For more info you can check Neon docs

Example

const batchResponse: BatchType = await db.batch([
	db.insert(usersTable).values({ id: 1, name: 'John' }).returning({
		id: usersTable.id,
	}),
	db.insert(usersTable).values({ id: 2, name: 'Dan' }),
	db.query.usersTable.findMany({}),
	db.query.usersTable.findFirst({}),
]);
type BatchType = [
	{
		id: number;
	}[],
	NeonHttpQueryResult<never>,
	{
		id: number;
		name: string;
		verified: number;
		invitedBy: number | null;
	}[],
	{
		id: number;
		name: string;
		verified: number;
		invitedBy: number | null;
	} | undefined,
];
Improvements

Thanks to the database-js and PlanetScale teams, we have updated the default behavior and instances of database-js.

As suggested by the database-js core team, you should use the Client instance instead of connect():

import { Client } from '@&#8203;planetscale/database';
import { drizzle } from 'drizzle-orm/planetscale-serverless';

// create the connection
const client = new Client({
	host: process.env['DATABASE_HOST'],
	username: process.env['DATABASE_USERNAME'],
	password: process.env['DATABASE_PASSWORD'],
});

const db = drizzle(client);

Warning: In this version, there are no breaking changes, but starting from version 0.30.0, you will encounter an error if you attempt to use anything other than a Client instance.

We suggest starting to change connections to PlanetScale now to prevent any runtime errors in the future.

Previously our docs stated to use connect() and only this function was can be passed to drizzle. In this realase we are adding support for new Client() and deprecating connect(), by suggesting from database-js team. In this release you will see a warning when trying to pass connect() function result:

Warning text

Warning: You need to pass an instance of Client:

import { Client } from "@&#8203;planetscale/database";

const client = new Client({
  host: process.env["DATABASE_HOST"],
  username: process.env["DATABASE_USERNAME"],
  password: process.env["DATABASE_PASSWORD"],
});

const db = drizzle(client);

Starting from version 0.30.0, you will encounter an error if you attempt to use anything other than a Client instance.

Please make the necessary changes now to prevent any runtime errors in the future

v0.29.3

Compare Source

  • fix: make expo peer dependencies optional #​1714

v0.29.2

Compare Source

Fixes

  • Added improvements to the planescale relational tests #​1579 - thanks @​Angelelz
  • [Pg] FIX: correct string escaping for empty PgArrays #​1640 - thanks @​Angelelz
  • Fix wrong syntax for exists fn in sqlite #​1647 - thanks @​Angelelz
  • Properly handle dates in AWS Data API
  • Fix Hermes mixins constructor issue

ESLint Drizzle Plugin, v0.2.3

🎉 [ESLint] Add support for functions and improve error messages #​1586 - thanks @​ngregrichardson

  • Allowed Drizzle object to be or to be retrieved from a function, e.g.
  • Added better context to the suggestion in the error message.

New Drivers

🎉 Expo SQLite Driver is available

For starting with Expo SQLite Driver, you need to install expo-sqlite and drizzle-orm packages.

npm install drizzle-orm expo-sqlite@next

Then, you can use it like this:

import { drizzle } from "drizzle-orm/expo-sqlite";
import { openDatabaseSync } from "expo-sqlite/next";

const expoDb = openDatabaseSync("db.db");

const db = drizzle(expoDb);

await db.select().from(...)...

// or

db.select().from(...).then(...);

// or

db.select().from(...).all();

If you want to use Drizzle Migrations, you need to update babel and metro configuration files.

  1. Install babel-plugin-inline-import package.
npm install babel-plugin-inline-import
  1. Update babel.config.js and metro.config.js files.

babel.config.js

module.exports = function(api) {
  api.cache(true);

  return {
    presets: ['babel-preset-expo'],
+   plugins: [["inline-import", { "extensions": [".sql"] }]]
  };
};

metro.config.js

const { getDefaultConfig } = require('expo/metro-config');

/** @&#8203;type {import('expo/metro-config').MetroConfig} */
const config = getDefaultConfig(__dirname);

+config.resolver.sourceExts.push('sql');

module.exports = config;
  1. Create drizzle.config.ts file in your project root folder.
import type { Config } from 'drizzle-kit';

export default {
	schema: './db/schema.ts',
	out: './drizzle',
	driver: 'expo',
} satisfies Config;

After creating schema file and drizzle.config.ts file, you can generate migrations like this:

npx drizzle-kit generate:sqlite

Then you need to import migrations.js file in your App.tsx file from ./drizzle folder and use hook useMigrations or migrate function.

import { drizzle } from "drizzle-orm/expo-sqlite";
import { openDatabaseSync } from "expo-sqlite/next";
import { useMigrations } from 'drizzle-orm/expo-sqlite/migrator';
import migrations from './drizzle/migrations';

const expoDb = openDatabaseSync("db.db");

const db = drizzle(expoDb);

export default function App() {
    const { success, error } = useMigrations(db, migrations);

    if (error) {
        return (
            <View>
                <Text>Migration error: {error.message}</Text>
            </View>
        );
    }

    if (!success) {
        return (
            <View>
                <Text>Migration is in progress...</Text>
            </View>
        );
    }

    return ...your application component;
}

v0.29.1

Compare Source

Fixes
New Features/Helpers
🎉 Detailed JSDoc for all query builders in all dialects - thanks @​realmikesolo

You can now access more information, hints, documentation links, etc. while developing and using JSDoc right in your IDE. Previously, we had them only for filter expressions, but now you can see them for all parts of the Drizzle query builder

🎉 New helpers for aggregate functions in SQL - thanks @​L-Mario564

Remember, aggregation functions are often used with the GROUP BY clause of the SELECT statement. So if you are selecting using aggregating functions and other columns in one query,
be sure to use the .groupBy clause

Here is a list of functions and equivalent using sql template

count

await db.select({ value: count() }).from(users);
await db.select({ value: count(users.id) }).from(users);

// It's equivalent to writing
await db.select({ 
  value: sql`count('*'))`.mapWith(Number) 
}).from(users);
await db.select({ 
  value: sql`count(${users.id})`.mapWith(Number) 
}).from(users);

countDistinct

await db.select({ value: countDistinct(users.id) }).from(users);

// It's equivalent to writing
await db.select({ 
  value: sql`count(${users.id})`.mapWith(Number) 
}).from(users);

avg

await db.select({ value: avg(users.id) }).from(users);

// It's equivalent to writing
await db.select({ 
  value: sql`avg(${users.id})`.mapWith(String) 
}).from(users);

avgDistinct

await db.select({ value: avgDistinct(users.id) }).from(users);

// It's equivalent to writing
await db.select({ 
  value: sql`avg(distinct ${users.id})`.mapWith(String) 
}).from(users);

sum

await db.select({ value: sum(users.id) }).from(users);

// It's equivalent to writing
await db.select({ 
  value: sql`sum(${users.id})`.mapWith(String) 
}).from(users);

sumDistinct

await db.select({ value: sumDistinct(users.id) }).from(users);

// It's equivalent to writing
await db.select({ 
  value: sql`sum(distinct ${users.id})`.mapWith(String) 
}).from(users);

max

await db.select({ value: max(users.id) }).from(users);

// It's equivalent to writing
await db.select({ 
  value: sql`max(${expression})`.mapWith(users.id) 
}).from(users);

min

await db.select({ value: min(users.id) }).from(users);

// It's equivalent to writing
await db.select({ 
  value: sql`min(${users.id})`.mapWith(users.id) 
}).from(users);
New Packages
🎉 ESLint Drizzle Plugin

For cases where it's impossible to perform type checks for specific scenarios, or where it's possible but error messages would be challenging to understand, we've decided to create an ESLint package with recommended rules. This package aims to assist developers in handling crucial scenarios during development

Big thanks to @​Angelelz for initiating the development of this package and transferring it to the Drizzle Team's npm

Install
[ npm | yarn | pnpm | bun ] install eslint eslint-plugin-drizzle

You can install those packages for typescript support in your IDE

[ npm | yarn | pnpm | bun ] install @&#8203;typescript-eslint/eslint-plugin @&#8203;typescript-eslint/parser
Usage

Create a .eslintrc.yml file, add drizzle to the plugins, and specify the rules you want to use. You can find a list of all existing rules below

root: true
parser: '@&#8203;typescript-eslint/parser'
parserOptions:
  project: './tsconfig.json'
plugins:
  - drizzle
rules:
  'drizzle/enforce-delete-with-where': "error"
  'drizzle/enforce-update-with-where': "error"
All config

This plugin exports an all config that makes use of all rules (except for deprecated ones).

root: true
extends:
  - "plugin:drizzle/all"
parser: '@&#8203;typescript-eslint/parser'
parserOptions:
  project: './tsconfig.json'
plugins:
  - drizzle

At the moment, all is equivalent to recommended

root: true
extends:
  - "plugin:drizzle/recommended"
parser: '@&#8203;typescript-eslint/parser'
parserOptions:
  project: './tsc

</details>

---

### Configuration

📅 **Schedule**: Branch creation - At any time (no schedule defined), Automerge - At any time (no schedule defined).

🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about this update again.

---

 - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box

---

This PR was generated by [Mend Renovate](https://mend.io/renovate/). View the [repository job log](https://developer.mend.io/github/qin-guan/cash-register).
<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiIzNy40Ni4wIiwidXBkYXRlZEluVmVyIjoiMzguNTYuMCIsInRhcmdldEJyYW5jaCI6Im1haW4ifQ==-->

Copy link

cloudflare-pages bot commented Nov 9, 2023

Deploying cash-register with  Cloudflare Pages  Cloudflare Pages

Latest commit: 892521f
Status: ✅  Deploy successful!
Preview URL: https://40a89500.cash-register-3az.pages.dev
Branch Preview URL: https://renovate-drizzle-orm-0-x.cash-register-3az.pages.dev

View logs

@renovate renovate bot force-pushed the renovate/drizzle-orm-0.x branch from 0c8d775 to 9c4a4dc Compare March 7, 2024 21:36
@renovate renovate bot changed the title chore(deps): update dependency drizzle-orm to ^0.29.0 chore(deps): update dependency drizzle-orm to ^0.30.0 Mar 7, 2024
@renovate renovate bot force-pushed the renovate/drizzle-orm-0.x branch from 9c4a4dc to c2d43f5 Compare May 31, 2024 09:36
@renovate renovate bot changed the title chore(deps): update dependency drizzle-orm to ^0.30.0 chore(deps): update dependency drizzle-orm to ^0.31.0 May 31, 2024
@renovate renovate bot force-pushed the renovate/drizzle-orm-0.x branch from c2d43f5 to 2f9d730 Compare July 10, 2024 13:20
@renovate renovate bot changed the title chore(deps): update dependency drizzle-orm to ^0.31.0 chore(deps): update dependency drizzle-orm to ^0.32.0 Jul 10, 2024
@renovate renovate bot force-pushed the renovate/drizzle-orm-0.x branch from 2f9d730 to 892521f Compare August 8, 2024 17:45
@renovate renovate bot changed the title chore(deps): update dependency drizzle-orm to ^0.32.0 chore(deps): update dependency drizzle-orm to ^0.33.0 Aug 8, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

0 participants