chore: import upstream snapshot with attribution

This commit is contained in:
wehub-resource-sync
2026-07-13 12:10:05 +08:00
commit d37d8d293b
1388 changed files with 484182 additions and 0 deletions
+3
View File
@@ -0,0 +1,3 @@
# drizzle-orm 0.12.0-beta.23
- Added new row mapping mechanism as `mapResultRowV2`, `mapResultRow` will be replaced by it in the future.
+5
View File
@@ -0,0 +1,5 @@
# drizzle-orm 0.12.0-beta.24
- Made `.execute()` method public in query builders.
- Added `name()` function for escaping entity names inside queries.
- (internal) Removed old row mapper implementation.
+3
View File
@@ -0,0 +1,3 @@
# drizzle-orm 0.13.0
- Release 🎉
+3
View File
@@ -0,0 +1,3 @@
# drizzle-orm 0.13.1
- Fix mysql peer dependency range
+3
View File
@@ -0,0 +1,3 @@
# drizzle-orm 0.14.1
- Bumped everything to 0.14.1.
+3
View File
@@ -0,0 +1,3 @@
# drizzle-orm 0.14.2
- Bumped everything to 0.14.2
+4
View File
@@ -0,0 +1,4 @@
# drizzle-orm 0.15.0
- Minor upgrade for all modules, due to adding version for api
- Add internal version for ORM api and npm version
+4
View File
@@ -0,0 +1,4 @@
# drizzle-orm 0.15.1
- Add schema symbol to table
- Append schema before table name in SQLWrapper if it exists
+3
View File
@@ -0,0 +1,3 @@
# drizzle-orm 0.15.2
Internal release
+3
View File
@@ -0,0 +1,3 @@
# drizzle-orm 0.15.3
Internal release
+3
View File
@@ -0,0 +1,3 @@
# drizzle-orm 0.16.0
- Bump all packages to 0.16.0
+3
View File
@@ -0,0 +1,3 @@
# drizzle-orm 0.16.0
- Fix peer dependency error for >=0.16 drizzle packages
+25
View File
@@ -0,0 +1,25 @@
## ❗ All ORM packages are now merged into `drizzle-orm`
Starting from release `0.17.0` and onwards, all dialect-specific packages are merged into `drizzle-orm`. Legacy ORM packages will be archived.
### Import paths changes
#### PostgreSQL
- `import { ... } from 'drizzle-orm-pg'` -> `import { ... } from 'drizzle-orm/pg-core'`
- `import { ... } from 'drizzle-orm-pg/node'` -> `import { ... } from 'drizzle-orm/node-postgres'`
- `import { ... } from 'drizzle-orm-pg/neondb'` -> `import { ... } from 'drizzle-orm/neon'`
- `import { ... } from 'drizzle-orm-pg/postgres.js'` -> `import { ... } from 'drizzle-orm/postgres.js'`
#### MySQL
- `import { ... } from 'drizzle-orm-mysql'` -> `import { ... } from 'drizzle-orm/mysql-core'`
- `import { ... } from 'drizzle-orm-mysql/mysql2'` -> `import { ... } from 'drizzle-orm/mysql2'`
#### SQLite
- `import { ... } from 'drizzle-orm-sqlite'` -> `import { ... } from 'drizzle-orm/sqlite-core'`
- `import { ... } from 'drizzle-orm-sqlite/better-sqlite3'` -> `import { ... } from 'drizzle-orm/better-sqlite3'`
- `import { ... } from 'drizzle-orm-sqlite/d1'` -> `import { ... } from 'drizzle-orm/d1'`
- `import { ... } from 'drizzle-orm-sqlite/bun'` -> `import { ... } from 'drizzle-orm/bun-sqlite'`
- `import { ... } from 'drizzle-orm-sqlite/sql.js'` -> `import { ... } from 'drizzle-orm/sql.js'`
+1
View File
@@ -0,0 +1 @@
- Added feature showcase section to README
+1
View File
@@ -0,0 +1 @@
- Fixed package.json require path in 'drizzle-orm/version'
+22
View File
@@ -0,0 +1,22 @@
We have released [AWS Data API support](https://docs.aws.amazon.com/AmazonRDS/latest/AuroraUserGuide/data-api.html) for PostgreSQL
---
Connection example
```typescript
import { drizzle, migrate } from 'drizzle-orm/aws-data-api/pg';
const rdsClient = new RDSDataClient({});
const db = drizzle(rdsClient, {
database: '',
secretArn: '',
resourceArn: '',
});
await migrate(db, { migrationsFolder: '' });
```
> **Note**:
> All drizzle pg data types are working well with data api, except of `interval`. This type is not yet mapped in proper way
+23
View File
@@ -0,0 +1,23 @@
We have released [SQLite Proxy Driver](https://github.com/drizzle-team/drizzle-orm/tree/main/examples/sqlite-proxy)
---
Perfect way to setup custom logic for database calls instead of predefined drivers
Should work well with serverless apps 🚀
```typescript
// Custom Proxy HTTP driver
const db = drizzle(async (sql, params, method) => {
try {
const rows = await axios.post('http://localhost:3000/query', { sql, params, method });
return { rows: rows.data };
} catch (e: any) {
console.error('Error from sqlite proxy server: ', e.response.data)
return { rows: [] };
}
});
```
> For more example you can check [full documentation](https://github.com/drizzle-team/drizzle-orm/tree/main/examples/sqlite-proxy)
+19
View File
@@ -0,0 +1,19 @@
We have released [Planetscale Serverless](https://github.com/planetscale/database-js) driver support
---
Usage example:
```typescript
import { drizzle } from 'drizzle-orm/planetscale-serverless';
import { connect } from '@planetscale/database';
// create the connection
const connection = connect({
host: process.env['DATABASE_HOST'],
username: process.env['DATABASE_USERNAME'],
password: process.env['DATABASE_PASSWORD'],
});
const db = drizzle(connection);
```
+3
View File
@@ -0,0 +1,3 @@
Fix circular dependency for query building on all pg and mysql drivers
Moved all aws data api typings specific logic to dialect from sql to prevent circular dependency issues
+4
View File
@@ -0,0 +1,4 @@
- Fix [#158](https://github.com/drizzle-team/drizzle-orm/issues/158) issue. Method `.returning()` was working incorrectly with `.get()` method in sqlite dialect
- Fix SQLite Proxy driver mapping bug
- Add test cases for SQLite Proxy driver
- Add additional example for SQLite Proxy Server setup to handle `.get()` as well
+4
View File
@@ -0,0 +1,4 @@
- Improved join result types for partial selects (refer to the [docs](/docs/joins.md) page for more information)
- Renamed import paths for Postgres.js and SQL.js drivers to avoid bundling errors:
- `drizzle-orm/postgres.js` -> `drizzle-orm/postgres-js`
- `drizzle-orm/sql.js` -> `drizzle-orm/sql-js`
+17
View File
@@ -0,0 +1,17 @@
- Implemented selecting and joining a subquery. Example usage:
```ts
const sq = db
.select({
categoryId: courseCategoriesTable.id,
category: courseCategoriesTable.name,
total: sql`count(${courseCategoriesTable.id})`.as<number>(),
})
.from(courseCategoriesTable)
.groupBy(courseCategoriesTable.id, courseCategoriesTable.name)
.subquery('sq');
```
After that, just use the subquery instead of a table as usual.
- ❗ Replaced `db.select(table).fields({ ... })` syntax with `db.select({ ... }).from(table)` to look more like its SQL counterpart.
+12
View File
@@ -0,0 +1,12 @@
## Changelog
---
- Add `char` data type support for postgresql by @AlexandrLi in [#177](https://github.com/drizzle-team/drizzle-orm/pull/177)
- Adding new section with `New Contributors` for release notes. Took this template from [bun](https://github.com/oven-sh/bun) release notes pattern
## New Contributors
---
- @AlexandrLi made their first contribution in [#177](https://github.com/drizzle-team/drizzle-orm/pull/177)
+23
View File
@@ -0,0 +1,23 @@
- 🎉 **Implemented support for WITH clause ([docs](/drizzle-orm/src/pg-core/README.md#with-clause)). Example usage:**
```ts
const sq = db
.select()
.from(users)
.prepareWithSubquery('sq');
const result = await db
.with(sq)
.select({
id: sq.id,
name: sq.name,
total: sql<number>`count(${sq.id})::int`(),
})
.from(sq)
.groupBy(sq.id, sq.name);
```
- 🐛 Fixed various bugs with selecting/joining of subqueries.
- ❗ Renamed `.subquery('alias')` to `.as('alias')`.
- ❗ ``sql`query`.as<type>()`` is now ``sql<type>`query`()``. Old syntax is still supported, but is deprecated and will be removed in one of the next releases.
+1
View File
@@ -0,0 +1 @@
- 🎉 Added `{ logger: true }` shorthand to `drizzle()` to enable query logging. See [logging docs](/drizzle-orm/src/pg-core/README.md#logging) for detailed logging configuration.
+5
View File
@@ -0,0 +1,5 @@
- 🎉 Added PostgreSQL network data types:
- `inet`
- `cidr`
- `macaddr`
- `macaddr8`
+23
View File
@@ -0,0 +1,23 @@
- 🎉 Added support for locking clauses in SELECT (`SELECT ... FOR UPDATE`):
PostgreSQL
```ts
await db
.select()
.from(users)
.for('update')
.for('no key update', { of: users })
.for('no key update', { of: users, skipLocked: true })
.for('share', { of: users, noWait: true });
```
MySQL
```ts
await db.select().from(users).for('update');
await db.select().from(users).for('share', { skipLocked: true });
await db.select().from(users).for('update', { noWait: true });
```
- 🎉🐛 Custom column types now support returning `SQL` from `toDriver()` method in addition to the `driverData` type from generic.
+242
View File
@@ -0,0 +1,242 @@
## Drizzle ORM 0.21.0 was released 🎉
- Added support for new migration folder structure and breakpoints feature, described in drizzle-kit release section
- Fix `onUpdateNow()` expression generation for default migration statement
</br>
### Support for PostgreSQL array types
---
```ts
export const salEmp = pgTable('sal_emp', {
name: text('name').notNull(),
payByQuarter: integer('pay_by_quarter').array(),
schedule: text('schedule').array().array(),
});
export const tictactoe = pgTable('tictactoe', {
squares: integer('squares').array(3).array(3),
});
```
drizzle kit will generate
```sql
CREATE TABLE sal_emp (
name text,
pay_by_quarter integer[],
schedule text[][]
);
CREATE TABLE tictactoe (
squares integer[3][3]
);
```
</br>
### Added composite primary key support to PostgreSQL and MySQL
---
PostgreSQL
```ts
import { primaryKey } from 'drizzle-orm/pg-core';
export const cpkTable = pgTable('table', {
column1: integer('column1').default(10).notNull(),
column2: integer('column2'),
column3: integer('column3'),
}, (table) => ({
cpk: primaryKey(table.column1, table.column2),
}));
```
MySQL
```ts
import { primaryKey } from 'drizzle-orm/mysql-core';
export const cpkTable = mysqlTable('table', {
simple: int('simple'),
columnNotNull: int('column_not_null').notNull(),
columnDefault: int('column_default').default(100),
}, (table) => ({
cpk: primaryKey(table.simple, table.columnDefault),
}));
```
---
## Drizzle Kit 0.17.0 was released 🎉
## Breaking changes
### Folder structure was migrated to newer version
Before running any new migrations `drizzle-kit` will ask you to upgrade in a first place
Migration file structure < 0.17.0
```plaintext
📦 <project root>
└ 📂 migrations
└ 📂 20221207174503
├ 📜 migration.sql
├ 📜 snapshot.json
└ 📂 20230101104503
├ 📜 migration.sql
├ 📜 snapshot.json
```
Migration file structure >= 0.17.0
```plaintext
📦 <project root>
└ 📂 migrations
└ 📂 meta
├ 📜 _journal.json
├ 📜 0000_snapshot.json
├ 📜 0001_snapshot.json
└ 📜 0000_icy_stranger.sql
└ 📜 0001_strange_avengers.sql
```
## Upgrading to 0.17.0
---
![](/changelogs/media/up_mysql.gif)
To easily migrate from previous folder structure to new you need to run `up` command in drizzle kit. It's a great helper to upgrade your migrations to new format on each drizzle kit major update
```bash
drizzle-kit up:<dialect> # dialects: `pg`, `mysql`, `sqlite`
# example for pg
drizzle-kit up:pg
```
</br>
## New Features
### New `drizzle-kit` command called `drop`
</br>
In a case you think some of migrations were generated in a wrong way or you have made migration simultaneously with other developers you can easily rollback it by running simple command
> **Warning**:
> Make sure you are dropping migrations that were not applied to your database
```bash
drizzle-kit drop
```
This command will show you a list of all migrations you have and you'll need just to choose migration you want to drop. After that `drizzle-kit` will do all the hard work on deleting migration files
![](/changelogs/media/drop.gif)
</br>
### New `drizzle-kit` option `--breakpoints` for `generate` and `introspect` commands
If particular driver doesn't support running multiple quries in 1 execution you can use `--breakpoints`.
`drizzle-kit` will generate current sql
```sql
CREATE TABLE `users` (
`id` int PRIMARY KEY NOT NULL,
`full_name` text NOT NULL,
);
--> statement-breakpoint
CREATE TABLE `table` (
`id` int PRIMARY KEY NOT NULL,
`phone` int,
);
```
Using it `drizzle-orm` will split all sql files by statements and execute them separately
</br>
### Add `drizzle-kit introspect` for MySQL dialect
You can introspect your mysql database using `introspect:mysql` command
```bash
drizzle-kit introspect:mysql --out ./migrations --connectionString mysql://user:password@127.0.0.1:3306/database
```
![](/changelogs/media/introspect_mysql.gif)
</br>
### Support for glob patterns for schema path
Usage example in `cli`
```bash
drizzle-kit generate:pg --out ./migrations --schema ./core/**/*.ts ./database/schema.ts
```
Usage example in `drizzle.config`
```text
{
"out: "./migrations",
"schema": ["./core/**/*.ts", "./database/schema.ts"]
}
```
## Bug Fixes and improvements
### Postgres dialect
---
**GitHub issue fixes**
- [pg] char is undefined during introspection [#9](https://github.com/drizzle-team/drizzle-kit-mirror/issues/9)
- when unknown type is detected, would be nice to emit a TODO comment instead of undefined [#8](https://github.com/drizzle-team/drizzle-kit-mirror/issues/8)
- "post_id" integer DEFAULT currval('posts_id_seq'::regclass) generates invalid TS [#7](https://github.com/drizzle-team/drizzle-kit-mirror/issues/7)
- "ip" INET NOT NULL is not supported [#6](https://github.com/drizzle-team/drizzle-kit-mirror/issues/6)
- "id" UUID NOT NULL DEFAULT uuid_generate_v4() type is not supported [#5](https://github.com/drizzle-team/drizzle-kit-mirror/issues/5)
- array fields end up as "undefined" in the schema [#4](https://github.com/drizzle-team/drizzle-kit-mirror/issues/4)
- timestamp is not in the import statement in schema.ts [#3](https://github.com/drizzle-team/drizzle-kit-mirror/issues/3)
- generated enums are not camel cased [#2](https://github.com/drizzle-team/drizzle-kit-mirror/issues/2)
**Introspect improvements**
- Add support for composite PK's generation;
- Add support for `cidr`, `inet`, `macaddr`, `macaddr8`, `smallserial`
- Add interval fields generation in schema, such as `minute to second`, `day to hour`, etc.
- Add default values for `numerics`
- Add default values for `enums`
### MySQL dialect
---
**Migration generation improvements**
- Add `autoincrement` create, delete and update handling
- Add `on update current_timestamp` handling for timestamps
- Add data type changing, using `modify`
- Add `not null` changing, using `modify`
- Add `default` drop and create statements
- Fix `defaults` generation bugs, such as escaping, date strings, expressions, etc
**Introspect improvements**
- Add `autoincrement` to all supported types
- Add `fsp` for time based data types
- Add precision and scale for `double`
- Make time `{ mode: "string" }` by default
- Add defaults to `json`, `decimal` and `binary` datatypes
- Add `enum` data type generation
+17
View File
@@ -0,0 +1,17 @@
- 🎉 Added support for `HAVING` clause
- 🎉 Added support for referencing selected fields in `.where()`, `.having()`, `.groupBy()` and `.orderBy()` using an optional callback:
```ts
await db
.select({
id: citiesTable.id,
name: sql<string>`upper(${citiesTable.name})`.as('upper_name'),
usersCount: sql<number>`count(${users2Table.id})::int`.as('users_count'),
})
.from(citiesTable)
.leftJoin(users2Table, eq(users2Table.cityId, citiesTable.id))
.where(({ name }) => sql`length(${name}) >= 3`)
.groupBy(citiesTable.id)
.having(({ usersCount }) => sql`${usersCount} > 0`)
.orderBy(({ name }) => name);
```
+43
View File
@@ -0,0 +1,43 @@
- 🎉 Introduced a standalone query builder that can be used without a DB connection:
```ts
import { queryBuilder as qb } from 'drizzle-orm/pg-core';
const query = qb.select().from(users).where(eq(users.name, 'Dan'));
const { sql, params } = query.toSQL();
```
- 🎉 Improved `WITH ... SELECT` subquery creation syntax to more resemble SQL:
**Before**:
```ts
const regionalSales = db
.select({
region: orders.region,
totalSales: sql`sum(${orders.amount})`.as<number>('total_sales'),
})
.from(orders)
.groupBy(orders.region)
.prepareWithSubquery('regional_sales');
await db.with(regionalSales).select(...).from(...);
```
**After**:
```ts
const regionalSales = db
.$with('regional_sales')
.as(
db
.select({
region: orders.region,
totalSales: sql<number>`sum(${orders.amount})`.as('total_sales'),
})
.from(orders)
.groupBy(orders.region),
);
await db.with(regionalSales).select(...).from(...);
```
+89
View File
@@ -0,0 +1,89 @@
- 🎉 Added Knex and Kysely adapters! They allow you to manage the schemas and migrations with Drizzle and query the data with your favorite query builder. See documentation for more details:
- [Knex adapter](https://github.com/drizzle-team/drizzle-knex)
- [Kysely adapter](https://github.com/drizzle-team/drizzle-kysely)
- 🎉 Added "type maps" to all entities. You can access them via the special `_` property. For example:
```ts
const users = mysqlTable('users', {
id: int('id').primaryKey(),
name: text('name').notNull(),
});
type UserFields = typeof users['_']['columns'];
type InsertUser = typeof users['_']['model']['insert'];
```
Full documentation on the type maps is coming soon.
- 🎉 Added `.$type()` method to all column builders to allow overriding the data type. It also replaces the optional generics on columns.
```ts
// Before
const test = mysqlTable('test', {
jsonField: json<Data>('json_field'),
});
// After
const test = mysqlTable('test', {
jsonField: json('json_field').$type<Data>(),
});
```
- ❗ Changed syntax for text-based enum columns:
```ts
// Before
const test = mysqlTable('test', {
role: text<'admin' | 'user'>('role'),
});
// After
const test = mysqlTable('test', {
role: text('role', { enum: ['admin', 'user'] }),
});
```
- 🎉 Allowed passing an array of values into `.insert().values()` directly without spreading:
```ts
const users = mysqlTable('users', {
id: int('id').primaryKey(),
name: text('name').notNull(),
});
await users.insert().values([
{ name: 'John' },
{ name: 'Jane' },
]);
```
The spread syntax is now deprecated and will be removed in one of the next releases.
- 🎉 Added "table creators" to allow for table name customization:
```ts
import { mysqlTableCreator } from 'drizzle-orm/mysql-core';
const mysqlTable = mysqlTableCreator((name) => `myprefix_${name}`);
const users = mysqlTable('users', {
id: int('id').primaryKey(),
name: text('name').notNull(),
});
// Users table is a normal table, but its name is `myprefix_users` in runtime
```
- 🎉 Implemented support for selecting/joining raw SQL expressions:
```ts
// select current_date + s.a as dates from generate_series(0,14,7) as s(a);
const result = await db
.select({
dates: sql`current_date + s.a`,
})
.from(sql`generate_series(0,14,7) as s(a)`);
```
- 🐛 Fixed a lot of bugs from user feedback on GitHub and Discord (thank you! ❤). Fixes #293 #301 #276 #269 #253 #311 #312
+1
View File
@@ -0,0 +1 @@
- 🐛 Re-export `InferModel` from `drizzle-orm`
+2
View File
@@ -0,0 +1,2 @@
- 🐛 Add missing config argument to transactions API
- 🐛 Fix Postgres and MySQL schema declaration (#427)
+3
View File
@@ -0,0 +1,3 @@
- 🐛 Fix migrator function for PostgreSQL
> Would suggest to upgrade to this version anyone who is using postgres dialect. `0.23.9` and `0.23.10` are broken for postgresql migrations
+1
View File
@@ -0,0 +1 @@
- 🐛 Fixed multi-level join results (e.g. joining a subquery with a nested join)
+1
View File
@@ -0,0 +1 @@
- 🎉 All enum and text enum columns now have a properly typed `enumValues` property
+1
View File
@@ -0,0 +1 @@
- 🐛 Rolled back some breaking changes for drizzle-kit
+1
View File
@@ -0,0 +1 @@
- 🎉 Added [libSQL](https://libsql.org/) support
+1
View File
@@ -0,0 +1 @@
- 🐛 Fixed broken types in Kysely and Knex adapters
+1
View File
@@ -0,0 +1 @@
- 🐛 Various minor bugfixes
+6
View File
@@ -0,0 +1,6 @@
- 🐛 Fixed referencing the selected aliased field in the same query
- 🐛 Fixed decimal column data type in MySQL
- 🐛 Fixed mode autocompletion for integer column in SQLite
- 🐛 Fixed extra parentheses in the generated SQL for the `IN` operator (#382)
- 🐛 Fixed regression in `pgEnum.enumValues` type (#358)
- 🎉 Allowed readonly arrays to be passed to `pgEnum`
+1
View File
@@ -0,0 +1 @@
- 🎉 Added `INSERT IGNORE` support for MySQL (#305)
+1
View File
@@ -0,0 +1 @@
- 🎉 Fixed dates timezone differences for timestamps in Postgres and MySQL (contributed by @AppelBoomHD via #288)
+19
View File
@@ -0,0 +1,19 @@
# Transactions support 🎉
You can now use transactions with all the supported databases and drivers.
`node-postgres` example:
```ts
await db.transaction(async (tx) => {
await tx.insert(users).values(newUser);
await tx.update(users).set({ name: 'Mr. Dan' }).where(eq(users.name, 'Dan'));
await tx.delete(users).where(eq(users.name, 'Dan'));
});
```
For more information, see transactions docs:
- [PostgreSQL](/drizzle-orm/src/pg-core/README.md#transactions)
- [MySQL](/drizzle-orm/src/mysql-core/README.md#transactions)
- [SQLite](/drizzle-orm/src/sqlite-core/README.md#transactions)
+2
View File
@@ -0,0 +1,2 @@
- 🎉 Added iterator support to `mysql2` (sponsored by @rizen ❤)
-`.prepare()` in MySQL no longer requires a name argument
+9
View File
@@ -0,0 +1,9 @@
### Bugs
🐛 Fix onConflict targets in [#475](https://github.com/drizzle-team/drizzle-orm/pull/475) - thanks @wkunert ❤️
### Documentation
> Thanks to @tmcw we have started our way to get JSDoc documentation
📄 JSDoc for conditions in [#467](https://github.com/drizzle-team/drizzle-orm/pull/467) - thanks @tmcw ❤️
+1
View File
@@ -0,0 +1 @@
- 🐛 Pool connections opened for transactions are now closed after the transaction is committed or rolled back
+1
View File
@@ -0,0 +1 @@
- 🐛 Fixed query generation when selecting from alias
+4
View File
@@ -0,0 +1,4 @@
- 🐛 Added verbose error when .values() is called without values (#441)
- 🐛 Fixed nested PG arrays mapping (#460)
- ❗ Removed spread syntax in .values() (#269)
- 🐛 Fixed passing undefined as field value to insert/update (#375)
+15
View File
@@ -0,0 +1,15 @@
- Add possibility to have placeholders in `.limit()` and `.offset()`
```ts
const stmt = db
.select({
id: usersTable.id,
name: usersTable.name,
})
.from(usersTable)
.limit(placeholder('limit'))
.offset(placeholder('offset'))
.prepare('stmt');
const result = await stmt.execute({ limit: 1, offset: 1 });
```
+5
View File
@@ -0,0 +1,5 @@
# ESM support
- 🎉 Added ESM support! You can now use `drizzle-orm` in both ESM and CJS environments.
- 🎉 Added code minification and source maps.
- ❗ Removed several nested import paths. Most notably, everything from `drizzle-orm/sql` and `drizzle-orm/expressions` should now be imported from `drizzle-orm` instead.
+1
View File
@@ -0,0 +1 @@
- 🐛 Fix package.json `exports` field
+3
View File
@@ -0,0 +1,3 @@
- 🎉 Documentation improvements (#495, #507)
- 🎉 Added `"sideEffects": false` to package.json (#515)
- 🐛 Fixed AWS Data API driver migrations (#510)
+2
View File
@@ -0,0 +1,2 @@
- 🐛 Fix `pg` imports in ESM mode (#505)
- 🐛 Add "types" and "default" fields to "exports" entries in package.json (#511)
+11
View File
@@ -0,0 +1,11 @@
- 🎉 Added support for [Vercel Postgres](https://vercel.com/docs/storage/vercel-postgres/quickstart)
```typescript
import { drizzle } from 'drizzle-orm/vercel-postgres';
import { sql } from "@vercel/postgres";
const db = drizzle(sql);
db.select(...)
```
+186
View File
@@ -0,0 +1,186 @@
# Drizzle ORM 0.26.0 is here 🎉
## README docs are fully tranferred to web
The documentation has been completely reworked and updated with additional examples and explanations. You can find it here: https://orm.drizzle.team.
Furthermore, the entire documentation has been made open source, allowing you to edit and add any information you deem important for the community.
Visit https://github.com/drizzle-team/drizzle-orm-docs to access the open-sourced documentation.
Additionally, you can create specific documentation issues in this repository
## New Features
Introducing our first helper built on top of Drizzle Core API syntax: **the Relational Queries!** 🎉
With Drizzle RQ you can do:
1. Any amount of relations that will be mapped for you
2. Including or excluding! specific columns. You can also combine these options
3. Harness the flexibility of the `where` statements, allowing you to define custom conditions beyond the predefined ones available in the Drizzle Core API.
4. Expand the functionality by incorporating additional extras columns using SQL templates. For more examples, refer to the documentation.
Most importantly, regardless of the size of your query, Drizzle will always generate a **SINGLE optimized query**.
This efficiency extends to the usage of **Prepared Statements**, which are fully supported within the Relational Query Builder.
For more info: [Prepared Statements in Relational Query Builder](https://orm.drizzle.team/rqb#prepared-statements)
**Example of setting one-to-many relations**
> As you can observe, `relations` are a distinct concept that coexists alongside the main Drizzle schema. You have the flexibility to opt-in or opt-out of them at any time without affecting the `drizzle-kit` migrations or the logic for Core API's types and runtime.
```ts
import { integer, serial, text, pgTable } from 'drizzle-orm/pg-core';
import { relations } from 'drizzle-orm';
export const users = pgTable('users', {
id: serial('id').primaryKey(),
name: text('name').notNull(),
});
export const usersConfig = relations(users, ({ many }) => ({
posts: many(posts),
}));
export const posts = pgTable('posts', {
id: serial('id').primaryKey(),
content: text('content').notNull(),
authorId: integer('author_id').notNull(),
});
export const postsConfig = relations(posts, ({ one }) => ({
author: one(users, { fields: [posts.authorId], references: [users.id] }),
}));
```
**Example of querying you database**
Step 1: Provide all tables and relations to `drizzle` function
> `drizzle` import depends on the database driver you're using
```ts
import * as schema from './schema';
import { drizzle } from 'drizzle-orm/...';
const db = drizzle(client, { schema });
await db.query.users.findMany(...);
```
If you have schema in multiple files
```ts
import * as schema1 from './schema1';
import * as schema2 from './schema2';
import { drizzle } from 'drizzle-orm/...';
const db = drizzle(client, { schema: { ...schema1, ...schema2 } });
await db.query.users.findMany(...);
```
Step 2: Query your database with Relational Query Builder
**Select all users**
```ts
const users = await db.query.users.findMany();
```
**Select first users**
> `.findFirst()` will add limit 1 to the query
```ts
const user = await db.query.users.findFirst();
```
**Select all users**
Get all posts with just `id`, `content` and include `comments`
```ts
const posts = await db.query.posts.findMany({
columns: {
id: true,
content: true,
},
with: {
comments: true,
}
});
```
**Select all posts excluding `content` column**
```ts
const posts = await db.query.posts.findMany({
columns: {
content: false,
},
});
```
For more examples you can check [full docs](https://orm.drizzle.team/rqb) for Relational Queries
## Bug fixes
- 🐛 Fixed partial joins with prefixed tables (#542)
## Drizzle Kit updates
### New ways to define drizzle config file
You can now specify the configuration not only in the `.json` format but also in `.ts` and `.js` formats.
</br>
**TypeScript example**
```ts
import { Config } from "drizzle-kit";
export default {
schema: "",
connectionString: process.env.DB_URL,
out: "",
breakpoints: true
} satisfies Config;
```
**JavaScript example**
```js
/** @type { import("drizzle-kit").Config } */
export default {
schema: "",
connectionString: "",
out: "",
breakpoints: true
};
```
## New commands 🎉
### `drizzle-kit push:mysql`
You can now push your MySQL schema directly to the database without the need to create and manage migration files. This feature proves to be particularly useful for rapid local development and when working with PlanetScale databases.
By pushing the MySQL schema directly to the database, you can streamline the development process and avoid the overhead of managing migration files. This allows for more efficient iteration and quick deployment of schema changes during local development.
### How to setup your codebase for drizzle-kit push feature?
1. For this feature, you need to create a `drizzle.config.[ts|js|json]` file. We recommend using `.ts` or `.js` files as they allow you to easily provide the database connection information as secret variables
You'll need to specify `schema` and `connectionString`(or `db`, `port`, `host`, `password`, etc.) to make `drizzle-kit push:mysql` work
`drizzle.config.ts` example
```ts copy
import { Config } from "src";
export default {
schema: "./schema.ts",
connectionString: process.env.DB_URL,
} satisfies Config;
```
2. Run `drizzle-kit push:mysql`
3. If Drizzle detects any potential `data-loss` issues during a migration, it will prompt you to approve whether the data should be truncated or not in order to ensure a successful migration
4. Approve or reject the action that Drizzle needs to perform in order to push your schema changes to the database.
5. Done ✅
+3
View File
@@ -0,0 +1,3 @@
- 🐛 Fixed including multiple relations on the same level in RQB (#599)
- 🐛 Updated migrators for relational queries support (#601)
- 🐛 Fixed invoking .findMany() without arguments
+5
View File
@@ -0,0 +1,5 @@
- 🐛 Fixed upsert targeting composite keys for SQLite (#521)
- 🐛 AWS Data API+Postgres: fixed adding of typings when merging queries (#517)
- 🐛 Fixed "on conflict" with "where" clause for Postgres (#651)
- 🐛 Various GitHub docs community fixes and improvements ♥ (#547, #548, #587, #606, #609, #625)
- **Experimental**: added OpenTelemetry support for Postgres
+1
View File
@@ -0,0 +1 @@
- Disabled OTEL integration due to the top-level await issues
+3
View File
@@ -0,0 +1,3 @@
- 🐛 Fixed AWS Data API mapping in relational queries (#677, #681)
- 🐛 Allowed using named self-relations (#678)
- 🐛 Fixed querying relations with composite FKs (#683)
+1
View File
@@ -0,0 +1 @@
- 🎉 Added bigint mode to SQLite (#558)
+58
View File
@@ -0,0 +1,58 @@
## Correct behavior when installed in a monorepo (multiple Drizzle instances)
Replacing all `instanceof` statements with a custom `is()` function allowed us to handle multiple Drizzle packages interacting properly.
**It also fixes one of our biggest Discord tickets: `maximum call stack exceeded` 🎉**
You should now use `is()` instead of `instanceof` to check if specific objects are instances of specific Drizzle types. It might be useful if you are building something on top of the Drizzle API.
```ts
import { is, Column } from 'drizzle-orm'
if (is(value, Column)) {
// value's type is narrowed to Column
}
```
## `distinct` clause support
```ts
await db.selectDistinct().from(usersDistinctTable).orderBy(
usersDistinctTable.id,
usersDistinctTable.name,
);
```
Also, `distinct on` clause is available for PostgreSQL:
```ts
await db.selectDistinctOn([usersDistinctTable.id]).from(usersDistinctTable).orderBy(
usersDistinctTable.id,
);
await db.selectDistinctOn([usersDistinctTable.name], { name: usersDistinctTable.name }).from(
usersDistinctTable,
).orderBy(usersDistinctTable.name);
```
## `bigint` and `boolean` support for SQLite
Contributed by @MrRahulRamkumar (#558), @raducristianpopa (#411) and @meech-ward (#725)
```ts
const users = sqliteTable('users', {
bigintCol: blob('bigint', { mode: 'bigint' }).notNull(),
boolCol: integer('bool', { mode: 'boolean' }).notNull(),
});
```
## DX improvements
- Added verbose type error when relational queries are used on a database type without a schema generic
- Fix `where` callback in RQB for tables without relations
## Various docs improvements
- Fix joins docs typo (#522) by @arjunyel
- Add Supabase guide to readme (#690) by @saltcod
- Make the column type in sqlite clearer (#717) by @shairez
+13
View File
@@ -0,0 +1,13 @@
- 🎉 Added support for [Neon HTTP driver](https://neon.tech/docs/serverless/serverless-driver)
```typescript
import { neon, neonConfig } from '@neondatabase/serverless';
import { drizzle } from 'drizzle-orm/neon-http';
neonConfig.fetchConnectionCache = true;
const sql = neon(process.env.DRIZZLE_DATABASE_URL!);
const db = drizzle(sql);
db.select(...)
```
+68
View File
@@ -0,0 +1,68 @@
## 🎉 Added support for `UNIQUE` constraints in PostgreSQL, MySQL, SQLite
For PostgreSQL, unique constraints can be defined at the column level for single-column constraints, and in the third parameter for multi-column constraints. In both cases, it will be possible to define a custom name for the constraint. Additionally, PostgreSQL will receive the `NULLS NOT DISTINCT` option to restrict having more than one NULL value in a table. [Reference](https://www.postgresql.org/docs/current/ddl-constraints.html#DDL-CONSTRAINTS-UNIQUE-CONSTRAINTS)
Examples that just shows a different `unique` usage. Please don't search a real usage for those tables
```ts
// single column
const table = pgTable('table', {
id: serial('id').primaryKey(),
name: text('name').notNull().unique(),
state: char('state', { length: 2 }).unique('custom'),
field: char('field', { length: 2 }).unique('custom_field', { nulls: 'not distinct' }),
});
// multiple columns
const table = pgTable('table', {
id: serial('id').primaryKey(),
name: text('name').notNull(),
state: char('state', { length: 2 }),
}, (t) => ({
first: unique('custom_name').on(t.name, t.state).nullsNotDistinct(),
second: unique('custom_name1').on(t.name, t.state),
}));
```
For MySQL, everything will be the same except for the `NULLS NOT DISTINCT` option. It appears that MySQL does not support it
Examples that just shows a different `unique` usage. Please don't search a real usage for those tables
```ts
// single column
const table = mysqlTable('table', {
id: serial('id').primaryKey(),
name: text('name').notNull().unique(),
state: text('state').unique('custom'),
field: text('field').unique('custom_field'),
});
// multiple columns
const table = mysqlTable('cities1', {
id: serial('id').primaryKey(),
name: text('name').notNull(),
state: text('state'),
}, (t) => ({
first: unique().on(t.name, t.state),
second: unique('custom_name1').on(t.name, t.state),
}));
```
In SQLite unique constraints are the same as unique indexes. As long as you can specify a name for the unique index in SQLite - we will treat all unique constraints as unique indexes in internal implementation
```ts
// single column
const table = sqliteTable('table', {
id: int('id').primaryKey(),
name: text('name').notNull().unique(),
state: text('state').unique('custom'),
field: text('field').unique(),
});
// multiple columns
const table = sqliteTable('table', {
id: int('id').primaryKey(),
name: text('name').notNull(),
state: text('state'),
}, (t) => ({
first: unique().on(t.name, t.state),
second: unique('custom').on(t.name, t.state),
}));
```
+174
View File
@@ -0,0 +1,174 @@
## Breaking changes
### Removed support for filtering by nested relations
Current example won't work in `0.28.0`:
```ts
const usersWithPosts = await db.query.users.findMany({
where: (table, { sql }) => (sql`json_array_length(${table.posts}) > 0`),
with: {
posts: true,
},
});
```
The `table` object in the `where` callback won't have fields from `with` and `extras`. We removed them to be able to build more efficient relational queries, which improved row reads and performance.
If you have used those fields in the `where` callback before, there are several workarounds:
1. Applying those filters manually on the code level after the rows are fetched;
2. Using the core API.
### Added Relational Queries `mode` config for `mysql2` driver
Drizzle relational queries always generate exactly one SQL statement to run on the database and it has certain caveats. To have best in class support for every database out there we've introduced modes.
Drizzle relational queries use lateral joins of subqueries under the hood and for now PlanetScale does not support them.
When using `mysql2` driver with regular MySQL database - you should specify mode: "default".
When using `mysql2` driver with PlanetScale - you need to specify mode: "planetscale".
```ts
import { drizzle } from 'drizzle-orm/mysql2';
import mysql from 'mysql2/promise';
import * as schema from './schema';
const connection = await mysql.createConnection({
uri: process.env.PLANETSCALE_DATABASE_URL,
});
const db = drizzle(connection, { schema, mode: 'planetscale' });
```
## Improved IntelliSense performance for large schemas
We've run the diagnostics on a database schema with 85 tables, 666 columns, 26 enums, 172 indexes and 133 foreign keys. We've optimized internal types which resulted in **430%** speed up in IntelliSense.
## Improved Relational Queries Permormance and Read Usage
In this release we've fully changed a way query is generated for Relational Queri API.
As a summary we've made current set of changes in query generation startegy:
1. Lateral Joins: In the new version we're utilizing lateral joins, denoted by the "LEFT JOIN LATERAL" clauses, to retrieve specific data from related tables efficiently For MySQL in PlanetScale and SQLite, we've used simple subquery selects, which improved a query plan and overall performance
2. Selective Data Retrieval: In the new version we're retrieving only the necessary data from tables. This targeted data retrieval reduces the amount of unnecessary information fetched, resulting in a smaller dataset to process and faster execution.
3. Reduced Aggregations: In the new version we've reduced the number of aggregation functions (e.g., COUNT, json_agg). By using json_build_array directly within the lateral joins, drizzle is aggregating the data in a more streamlined manner, leading to improved query performance.
4. Simplified Grouping: In the new version the GROUP BY clause is removed, as the lateral joins and subqueries already handle data aggregation more efficiently.
For this drizzle query
```ts
const items = await db.query.comments.findMany({
limit,
orderBy: comments.id,
with: {
user: {
columns: { name: true },
},
post: {
columns: { title: true },
with: {
user: {
columns: { name: true },
},
},
},
},
});
```
Query that Drizzle generates now
```sql
select "comments"."id",
"comments"."user_id",
"comments"."post_id",
"comments"."content",
"comments_user"."data" as "user",
"comments_post"."data" as "post"
from "comments"
left join lateral (select json_build_array("comments_user"."name") as "data"
from (select *
from "users" "comments_user"
where "comments_user"."id" = "comments"."user_id"
limit 1) "comments_user") "comments_user" on true
left join lateral (select json_build_array("comments_post"."title", "comments_post_user"."data") as "data"
from (select *
from "posts" "comments_post"
where "comments_post"."id" = "comments"."post_id"
limit 1) "comments_post"
left join lateral (select json_build_array("comments_post_user"."name") as "data"
from (select *
from "users" "comments_post_user"
where "comments_post_user"."id" = "comments_post"."user_id"
limit 1) "comments_post_user") "comments_post_user"
on true) "comments_post" on true
order by "comments"."id"
limit 1
```
Query generated before:
```sql
SELECT "id",
"user_id",
"post_id",
"content",
"user"::JSON,
"post"::JSON
FROM
(SELECT "comments".*,
CASE
WHEN count("comments_post"."id") = 0 THEN '[]'
ELSE json_agg(json_build_array("comments_post"."title", "comments_post"."user"::JSON))::text
END AS "post"
FROM
(SELECT "comments".*,
CASE
WHEN count("comments_user"."id") = 0 THEN '[]'
ELSE json_agg(json_build_array("comments_user"."name"))::text
END AS "user"
FROM "comments"
LEFT JOIN
(SELECT "comments_user".*
FROM "users" "comments_user") "comments_user" ON "comments"."user_id" = "comments_user"."id"
GROUP BY "comments"."id",
"comments"."user_id",
"comments"."post_id",
"comments"."content") "comments"
LEFT JOIN
(SELECT "comments_post".*
FROM
(SELECT "comments_post".*,
CASE
WHEN count("comments_post_user"."id") = 0 THEN '[]'
ELSE json_agg(json_build_array("comments_post_user"."name"))
END AS "user"
FROM "posts" "comments_post"
LEFT JOIN
(SELECT "comments_post_user".*
FROM "users" "comments_post_user") "comments_post_user" ON "comments_post"."user_id" = "comments_post_user"."id"
GROUP BY "comments_post"."id") "comments_post") "comments_post" ON "comments"."post_id" = "comments_post"."id"
GROUP BY "comments"."id",
"comments"."user_id",
"comments"."post_id",
"comments"."content",
"comments"."user") "comments"
LIMIT 1
```
## Possibility to insert rows with default values for all columns
You can now provide an empty object or an array of empty objects, and Drizzle will insert all defaults into the database.
```ts
// Insert 1 row with all defaults
await db.insert(usersTable).values({});
// Insert 2 rows with all defaults
await db.insert(usersTable).values([{}, {}]);
```
+1
View File
@@ -0,0 +1 @@
- 🐛 Fixed Postgres array-related issues introduced by 0.28.0 (#983, #992)
+16
View File
@@ -0,0 +1,16 @@
## The community contributions release 🎉
### Internal Features and Changes
1. Added a set of tests for d1. Thanks to @AdiRishi!
2. Fixed issues in internal documentation. Thanks to @balazsorban44 and @pyk!
### Bug Fixes
1. Resolved the issue of truncating timestamp milliseconds for MySQL. Thanks to @steviec!
2. Corrected the type of the get() method for sqlite-based dialects. Issue #565 has been closed. Thanks to @stefanmaric!
3. Rectified the sqlite-proxy bug that caused the query to execute twice. Thanks to @mosch!
### New packages 🎉
Added a support for [Typebox](https://github.com/sinclairzx81/typebox) in [drizzle-typebox](https://orm.drizzle.team/docs/typebox) package. Thanks to @Bulbang!
Please check documentation page for more usage examples: https://orm.drizzle.team/docs/typebox
+41
View File
@@ -0,0 +1,41 @@
- 🎉 Added SQLite simplified query API
- 🎉 Added `.$defaultFn()` / `.$default()` methods to column builders
You can specify any logic and any implementation for a function like `cuid()` for runtime defaults. Drizzle won't limit you in the number of implementations you can add.
> Note: This value does not affect the `drizzle-kit` behavior, it is only used at runtime in `drizzle-orm`
```ts
import { varchar, mysqlTable } from "drizzle-orm/mysql-core";
import { createId } from '@paralleldrive/cuid2';
const table = mysqlTable('table', {
id: varchar('id', { length: 128 }).$defaultFn(() => createId()),
});
```
- 🎉 Added `table.$inferSelect` / `table._.inferSelect` and `table.$inferInsert` / `table._.inferInsert` for more convenient table model type inference
- 🛠 Deprecated `InferModel` type in favor of more explicit `InferSelectModel` and `InferInsertModel`
```ts
import { InferSelectModel, InferInsertModel } from 'drizzle-orm'
const usersTable = pgTable('users', {
id: serial('id').primaryKey(),
name: text('name').notNull(),
verified: boolean('verified').notNull().default(false),
jsonb: jsonb('jsonb').$type<string[]>(),
createdAt: timestamp('created_at', { withTimezone: true }).notNull().defaultNow(),
});
type SelectUser = typeof usersTable.$inferSelect;
type InsertUser = typeof usersTable.$inferInsert;
type SelectUser2 = InferSelectModel<typeof usersTable>;
type InsertUser2 = InferInsertModel<typeof usersTable>;
```
- 🛠 Disabled `.d.ts` files bundling
- 🐛 Fixed sqlite-proxy and SQL.js response from `.get()` when the result is empty
+2
View File
@@ -0,0 +1,2 @@
- 🐛 Fixed imports in ESM-based projects (#1088)
- 🐛 Fixed type error on Postgres table definitions (#1089)
+1
View File
@@ -0,0 +1 @@
- 🐛 Fixed incorrect OpenTelemetry type import that caused a runtime error
+140
View File
@@ -0,0 +1,140 @@
## Changes
> **Note**:
> MySQL `datetime` with `mode: 'date'` will now store dates in UTC strings and retrieve data in UTC as well to align with MySQL behavior for `datetime`. If you need a different behavior and want to handle `datetime` mapping in a different way, please use `mode: 'string'` or [Custom Types](https://orm.drizzle.team/docs/custom-types) implementation
Check [Fix Datetime mapping for MySQL](https://github.com/drizzle-team/drizzle-orm/pull/1082) for implementation details
## New Features
### 🎉 `LibSQL` batch api support
Reference: https://docs.turso.tech/reference/client-access/javascript-typescript-sdk#execute-a-batch-of-statements
Batch API usage example:
```ts
const batchResponse = await db.batch([
db.insert(usersTable).values({ id: 1, name: 'John' }).returning({
id: usersTable.id,
}),
db.update(usersTable).set({ name: 'Dan' }).where(eq(usersTable.id, 1)),
db.query.usersTable.findMany({}),
db.select().from(usersTable).where(eq(usersTable.id, 1)),
db.select({ id: usersTable.id, invitedBy: usersTable.invitedBy }).from(
usersTable,
),
]);
```
Type for `batchResponse` in this example would be:
```ts
type BatchResponse = [
{
id: number;
}[],
ResultSet,
{
id: number;
name: string;
verified: number;
invitedBy: number | null;
}[],
{
id: number;
name: string;
verified: number;
invitedBy: number | null;
}[],
{
id: number;
invitedBy: number | null;
}[],
];
```
All possible builders that can be used inside `db.batch`:
```ts
`db.all()`,
`db.get()`,
`db.values()`,
`db.run()`,
`db.query.<table>.findMany()`,
`db.query.<table>.findFirst()`,
`db.select()...`,
`db.update()...`,
`db.delete()...`,
`db.insert()...`,
```
More usage examples here: [integration-tests/tests/libsql-batch.test.ts](https://github.com/drizzle-team/drizzle-orm/pull/1161/files#diff-17253895532e520545027dd48dcdbac2d69a5a49d594974e6d55d7502f89b838R248) and in [docs](https://orm.drizzle.team/docs/batch-api)
### 🎉 Add json mode for text in SQLite
Example
```ts
const test = sqliteTable('test', {
dataTyped: text('data_typed', { mode: 'json' }).$type<{ a: 1 }>().notNull(),
});
```
### 🎉 Add `.toSQL()` to Relational Query API calls
Example
```ts
const query = db.query.usersTable.findFirst().toSQL();
```
### 🎉 Added new PostgreSQL operators for Arrays - thanks @L-Mario564
List of operators and usage examples
`arrayContains`, `arrayContained`, `arrayOverlaps`
```ts
const contains = await db.select({ id: posts.id }).from(posts)
.where(arrayContains(posts.tags, ['Typescript', 'ORM']));
const contained = await db.select({ id: posts.id }).from(posts)
.where(arrayContained(posts.tags, ['Typescript', 'ORM']));
const overlaps = await db.select({ id: posts.id }).from(posts)
.where(arrayOverlaps(posts.tags, ['Typescript', 'ORM']));
const withSubQuery = await db.select({ id: posts.id }).from(posts)
.where(arrayContains(
posts.tags,
db.select({ tags: posts.tags }).from(posts).where(eq(posts.id, 1)),
));
```
### 🎉 Add more SQL operators for where filter function in Relational Queries - thanks @cayter!
**Before**
```ts
import { inArray } from "drizzle-orm/pg-core";
await db.users.findFirst({
where: (table, _) => inArray(table.id, [ ... ])
})
```
**After**
```ts
await db.users.findFirst({
where: (table, { inArray }) => inArray(table.id, [ ... ])
})
```
## Bug Fixes
- 🐛 [Correct where in on conflict in sqlite](https://github.com/drizzle-team/drizzle-orm/pull/1076) - Thanks @hanssonduck!
- 🐛 [Fix libsql/client type import](https://github.com/drizzle-team/drizzle-orm/pull/1122) - Thanks @luisfvieirasilva!
- 🐛 [Fix: raw sql query not being mapped properly on RDS](https://github.com/drizzle-team/drizzle-orm/pull/1071) - Thanks @boian-ivanov
- 🐛 [Fix Datetime mapping for MySQL](https://github.com/drizzle-team/drizzle-orm/pull/1082) - thanks @Angelelz
- 🐛 [Fix smallserial generating as serial](https://github.com/drizzle-team/drizzle-orm/pull/1127) - thanks @L-Mario564
+321
View File
@@ -0,0 +1,321 @@
> Drizzle ORM version `0.29.0` will require a minimum Drizzle Kit version of `0.20.0`, and vice versa. Therefore, when upgrading to a newer version of Drizzle ORM, you will also need to upgrade Drizzle Kit. This may result in some breaking changes throughout the versions, especially if you need to upgrade Drizzle Kit and your Drizzle ORM version is older than `<0.28.0`
## New Features
### 🎉 MySQL `unsigned` option for bigint
You can now specify `bigint unsigned` type
```ts
const table = mysqlTable('table', {
id: bigint('id', { mode: 'number', unsigned: true }),
});
```
Read more in [docs](https://orm.drizzle.team/docs/column-types/mysql#bigint)
### 🎉 Improved query builder types
Starting from `0.29.0` by default, as all the query builders in Drizzle try to conform to SQL as much as possible, you can only invoke most of the methods once. For example, in a SELECT statement there might only be one WHERE clause, so you can only invoke .where() once:
```ts
const query = db
.select()
.from(users)
.where(eq(users.id, 1))
.where(eq(users.name, 'John')); // ❌ Type error - where() can only be invoked once
```
This behavior is useful for conventional query building, i.e. when you create the whole query at once. However, it becomes a problem when you want to build a query dynamically, i.e. if you have a shared function that takes a query builder and enhances it. To solve this problem, Drizzle provides a special 'dynamic' mode for query builders, which removes the restriction of invoking methods only once. To enable it, you need to call .$dynamic() on a query builder.
Let's see how it works by implementing a simple withPagination function that adds LIMIT and OFFSET clauses to a query based on the provided page number and an optional page size:
```ts
function withPagination<T extends PgSelect>(
qb: T,
page: number,
pageSize: number = 10,
) {
return qb.limit(pageSize).offset(page * pageSize);
}
const query = db.select().from(users).where(eq(users.id, 1));
withPagination(query, 1); // ❌ Type error - the query builder is not in dynamic mode
const dynamicQuery = query.$dynamic();
withPagination(dynamicQuery, 1); // ✅ OK
```
Note that the withPagination function is generic, which allows you to modify the result type of the query builder inside it, for example by adding a join:
```ts
function withFriends<T extends PgSelect>(qb: T) {
return qb.leftJoin(friends, eq(friends.userId, users.id));
}
let query = db.select().from(users).where(eq(users.id, 1)).$dynamic();
query = withFriends(query);
```
Read more in [docs](https://orm.drizzle.team/docs/dynamic-query-building)
### 🎉 Possibility to specify name for primary keys and foreign keys
There is an issue when constraint names exceed the 64-character limit of the database. This causes the database engine to truncate the name, potentially leading to issues. Starting from `0.29.0`, you have the option to specify custom names for both `primaryKey()` and `foreignKey()`. We have also deprecated the old `primaryKey()` syntax, which can still be used but will be removed in future releases
```ts
const table = pgTable('table', {
id: integer('id'),
name: text('name'),
}, (table) => ({
cpk: primaryKey({ name: 'composite_key', columns: [table.id, table.name] }),
cfk: foreignKey({
name: 'fkName',
columns: [table.id],
foreignColumns: [table.name],
}),
}));
```
Read more in [docs](https://orm.drizzle.team/docs/indexes-constraints#composite-primary-key)
### 🎉 Read Replicas Support
You can now use the Drizzle `withReplica` function to specify different database connections for read replicas and the main instance for write operations. By default, `withReplicas` will use a random read replica for read operations and the main instance for all other data modification operations. You can also specify custom logic for choosing which read replica connection to use. You have the freedom to make any weighted, custom decision for that. Here are some usage examples:
```ts
const primaryDb = drizzle(client);
const read1 = drizzle(client);
const read2 = drizzle(client);
const db = withReplicas(primaryDb, [read1, read2]);
// read from primary
db.$primary.select().from(usersTable);
// read from either read1 connection or read2 connection
db.select().from(usersTable)
// use primary database for delete operation
db.delete(usersTable).where(eq(usersTable.id, 1))
```
Implementation example of custom logic for selecting read replicas, where the first replica has a 70% chance of being chosen, and the second replica has a 30% chance of being chosen. Note that you can implement any type of random selection for read replicas
```ts
const db = withReplicas(primaryDb, [read1, read2], (replicas) => {
const weight = [0.7, 0.3];
let cumulativeProbability = 0;
const rand = Math.random();
for (const [i, replica] of replicas.entries()) {
cumulativeProbability += weight[i]!;
if (rand < cumulativeProbability) return replica;
}
return replicas[0]!
});
```
`withReplicas` function is available for all dialects in Drizzle ORM
Read more in [docs](https://orm.drizzle.team/docs/read-replicas)
### 🎉 Set operators support (UNION, UNION ALL, INTERSECT, INTERSECT ALL, EXCEPT, EXCEPT ALL)
Huge thanks to @Angelelz for the significant contribution he made, from API discussions to proper type checks and runtime logic, along with an extensive set of tests. This greatly assisted us in delivering this feature in this release
Usage examples:
All set operators can be used in a two ways: `import approach` or `builder approach`
##### Import approach
```ts
import { union } from 'drizzle-orm/pg-core'
const allUsersQuery = db.select().from(users);
const allCustomersQuery = db.select().from(customers);
const result = await union(allUsersQuery, allCustomersQuery)
```
##### Builder approach
```ts
const result = await db.select().from(users).union(db.select().from(customers));
```
Read more in [docs](https://orm.drizzle.team/docs/set-operations)
### 🎉 New MySQL Proxy Driver
A new driver has been released, allowing you to create your own implementation for an HTTP driver using a MySQL database. You can find usage examples in the `./examples/mysql-proxy` folder
You need to implement two endpoints on your server that will be used for queries and migrations(Migrate endpoint is optional and only if you want to use drizzle migrations). Both the server and driver implementation are up to you, so you are not restricted in any way. You can add custom mappings, logging, and much more
You can find both server and driver implementation examples in the `./examples/mysql-proxy` folder
```ts
// Driver
import axios from 'axios';
import { eq } from 'drizzle-orm/expressions';
import { drizzle } from 'drizzle-orm/mysql-proxy';
import { migrate } from 'drizzle-orm/mysql-proxy/migrator';
import { cities, users } from './schema';
async function main() {
const db = drizzle(async (sql, params, method) => {
try {
const rows = await axios.post(`${process.env.REMOTE_DRIVER}/query`, {
sql,
params,
method,
});
return { rows: rows.data };
} catch (e: any) {
console.error('Error from pg proxy server:', e.response.data);
return { rows: [] };
}
});
await migrate(db, async (queries) => {
try {
await axios.post(`${process.env.REMOTE_DRIVER}/migrate`, { queries });
} catch (e) {
console.log(e);
throw new Error('Proxy server cannot run migrations');
}
}, { migrationsFolder: 'drizzle' });
await db.insert(cities).values({ id: 1, name: 'name' });
await db.insert(users).values({
id: 1,
name: 'name',
email: 'email',
cityId: 1,
});
const usersToCityResponse = await db.select().from(users).leftJoin(
cities,
eq(users.cityId, cities.id),
);
}
```
### 🎉 New PostgreSQL Proxy Driver
Same as MySQL you can now implement your own http driver for PostgreSQL database. You can find usage examples in the `./examples/pg-proxy` folder
You need to implement two endpoints on your server that will be used for queries and migrations (Migrate endpoint is optional and only if you want to use drizzle migrations). Both the server and driver implementation are up to you, so you are not restricted in any way. You can add custom mappings, logging, and much more
You can find both server and driver implementation examples in the `./examples/pg-proxy` folder
```ts
import axios from 'axios';
import { eq } from 'drizzle-orm/expressions';
import { drizzle } from 'drizzle-orm/pg-proxy';
import { migrate } from 'drizzle-orm/pg-proxy/migrator';
import { cities, users } from './schema';
async function main() {
const db = drizzle(async (sql, params, method) => {
try {
const rows = await axios.post(`${process.env.REMOTE_DRIVER}/query`, { sql, params, method });
return { rows: rows.data };
} catch (e: any) {
console.error('Error from pg proxy server:', e.response.data);
return { rows: [] };
}
});
await migrate(db, async (queries) => {
try {
await axios.post(`${process.env.REMOTE_DRIVER}/query`, { queries });
} catch (e) {
console.log(e);
throw new Error('Proxy server cannot run migrations');
}
}, { migrationsFolder: 'drizzle' });
const insertedCity = await db.insert(cities).values({ id: 1, name: 'name' }).returning();
const insertedUser = await db.insert(users).values({ id: 1, name: 'name', email: 'email', cityId: 1 });
const usersToCityResponse = await db.select().from(users).leftJoin(cities, eq(users.cityId, cities.id));
}
```
### 🎉 `D1` Batch API support
Reference: https://developers.cloudflare.com/d1/platform/client-api/#dbbatch
Batch API usage example:
```ts
const batchResponse = await db.batch([
db.insert(usersTable).values({ id: 1, name: 'John' }).returning({
id: usersTable.id,
}),
db.update(usersTable).set({ name: 'Dan' }).where(eq(usersTable.id, 1)),
db.query.usersTable.findMany({}),
db.select().from(usersTable).where(eq(usersTable.id, 1)),
db.select({ id: usersTable.id, invitedBy: usersTable.invitedBy }).from(
usersTable,
),
]);
```
Type for `batchResponse` in this example would be:
```ts
type BatchResponse = [
{
id: number;
}[],
D1Result,
{
id: number;
name: string;
verified: number;
invitedBy: number | null;
}[],
{
id: number;
name: string;
verified: number;
invitedBy: number | null;
}[],
{
id: number;
invitedBy: number | null;
}[],
];
```
All possible builders that can be used inside `db.batch`:
```ts
`db.all()`,
`db.get()`,
`db.values()`,
`db.run()`,
`db.query.<table>.findMany()`,
`db.query.<table>.findFirst()`,
`db.select()...`,
`db.update()...`,
`db.delete()...`,
`db.insert()...`,
```
More usage examples here: [integration-tests/tests/d1-batch.test.ts](https://github.com/drizzle-team/drizzle-orm/blob/beta/integration-tests/tests/d1-batch.test.ts) and in [docs](https://orm.drizzle.team/docs/batch-api)
---
## Drizzle Kit 0.20.0
1. New way to define drizzle.config using `defineConfig` function
2. Possibility to access Cloudflare D1 with Drizzle Studio using wrangler.toml file
3. Drizzle Studio is migrating to https://local.drizzle.studio/
4. `bigint unsigned` support
5. `primaryKeys` and `foreignKeys` now can have custom names
6. Environment variables are now automatically fetched
7. Some bug fixes and improvements
You can read more about drizzle-kit updates [here](https://github.com/drizzle-team/drizzle-kit-mirror/releases/tag/v0.20.0)
+276
View File
@@ -0,0 +1,276 @@
# Fixes
- Forward args correctly when using withReplica feature #1536. Thanks @Angelelz
- Fix selectDistinctOn not working with multiple columns #1466. Thanks @L-Mario564
# 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**
```ts
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**
```ts
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**
```ts
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**
```ts
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**
```ts
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**
```ts
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**
```ts
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**
```ts
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
```sh
[ npm | yarn | pnpm | bun ] install eslint eslint-plugin-drizzle
```
You can install those packages for typescript support in your IDE
```sh
[ npm | yarn | pnpm | bun ] install @typescript-eslint/eslint-plugin @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
```yml
root: true
parser: '@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](src/configs/all.js) that makes use of all rules (except for deprecated ones).
```yml
root: true
extends:
- "plugin:drizzle/all"
parser: '@typescript-eslint/parser'
parserOptions:
project: './tsconfig.json'
plugins:
- drizzle
```
At the moment, `all` is equivalent to `recommended`
```yml
root: true
extends:
- "plugin:drizzle/recommended"
parser: '@typescript-eslint/parser'
parserOptions:
project: './tsconfig.json'
plugins:
- drizzle
```
## Rules
**enforce-delete-with-where**: Enforce using `delete` with the`.where()` clause in the `.delete()` statement. Most of the time, you don't need to delete all rows in the table and require some kind of `WHERE` statements.
**Error Message**:
```
Without `.where(...)` you will delete all the rows in a table. If you didn't want to do it, please use `db.delete(...).where(...)` instead. Otherwise you can ignore this rule here
```
Optionally, you can define a `drizzleObjectName` in the plugin options that accept a `string` or `string[]`. This is useful when you have objects or classes with a delete method that's not from Drizzle. Such a `delete` method will trigger the ESLint rule. To avoid that, you can define the name of the Drizzle object that you use in your codebase (like db) so that the rule would only trigger if the delete method comes from this object:
Example, config 1:
```json
"rules": {
"drizzle/enforce-delete-with-where": ["error"]
}
```
```ts
class MyClass {
public delete() {
return {}
}
}
const myClassObj = new MyClass();
// ---> Will be triggered by ESLint Rule
myClassObj.delete()
const db = drizzle(...)
// ---> Will be triggered by ESLint Rule
db.delete()
```
Example, config 2:
```json
"rules": {
"drizzle/enforce-delete-with-where": ["error", { "drizzleObjectName": ["db"] }],
}
```
```ts
class MyClass {
public delete() {
return {}
}
}
const myClassObj = new MyClass();
// ---> Will NOT be triggered by ESLint Rule
myClassObj.delete()
const db = drizzle(...)
// ---> Will be triggered by ESLint Rule
db.delete()
```
**enforce-update-with-where**: Enforce using `update` with the`.where()` clause in the `.update()` statement. Most of the time, you don't need to update all rows in the table and require some kind of `WHERE` statements.
**Error Message**:
```
Without `.where(...)` you will update all the rows in a table. If you didn't want to do it, please use `db.update(...).set(...).where(...)` instead. Otherwise you can ignore this rule here
```
Optionally, you can define a `drizzleObjectName` in the plugin options that accept a `string` or `string[]`. This is useful when you have objects or classes with a delete method that's not from Drizzle. Such as `update` method will trigger the ESLint rule. To avoid that, you can define the name of the Drizzle object that you use in your codebase (like db) so that the rule would only trigger if the delete method comes from this object:
Example, config 1:
```json
"rules": {
"drizzle/enforce-update-with-where": ["error"]
}
```
```ts
class MyClass {
public update() {
return {}
}
}
const myClassObj = new MyClass();
// ---> Will be triggered by ESLint Rule
myClassObj.update()
const db = drizzle(...)
// ---> Will be triggered by ESLint Rule
db.update()
```
Example, config 2:
```json
"rules": {
"drizzle/enforce-update-with-where": ["error", { "drizzleObjectName": ["db"] }],
}
```
```ts
class MyClass {
public update() {
return {}
}
}
const myClassObj = new MyClass();
// ---> Will NOT be triggered by ESLint Rule
myClassObj.update()
const db = drizzle(...)
// ---> Will be triggered by ESLint Rule
db.update()
```
+138
View File
@@ -0,0 +1,138 @@
## 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
```
npm i eslint-plugin-drizzle@0.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.
```bash
npm install drizzle-orm expo-sqlite@next
```
Then, you can use it like this:
```ts
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.
```bash
npm install babel-plugin-inline-import
```
2. Update `babel.config.js` and `metro.config.js` files.
babel.config.js
```diff
module.exports = function(api) {
api.cache(true);
return {
presets: ['babel-preset-expo'],
+ plugins: [["inline-import", { "extensions": [".sql"] }]]
};
};
```
metro.config.js
```diff
const { getDefaultConfig } = require('expo/metro-config');
/** @type {import('expo/metro-config').MetroConfig} */
const config = getDefaultConfig(__dirname);
+config.resolver.sourceExts.push('sql');
module.exports = config;
```
3. Create `drizzle.config.ts` file in your project root folder.
```ts
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:
```bash
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.
```tsx
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;
}
```
+1
View File
@@ -0,0 +1 @@
- fix: make expo peer dependencies optional #1714
+85
View File
@@ -0,0 +1,85 @@
## New Features
### 🎉 **Neon HTTP Batch**
For more info you can check [Neon docs](https://neon.tech/docs/serverless/serverless-driver#issue-multiple-queries-with-the-transaction-function)
**Example**
```ts
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({}),
]);
```
```ts
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()`:
```typescript
import { Client } from '@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**
```mdx
Warning: You need to pass an instance of Client:
import { Client } from "@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
```
+112
View File
@@ -0,0 +1,112 @@
## New Features
### 🎉 WITH UPDATE, WITH DELETE, WITH INSERT - thanks @L-Mario564
You can now use `WITH` statements with [INSERT](https://orm.drizzle.team/docs/insert#with-insert-clause), [UPDATE](https://orm.drizzle.team/docs/update#with-update-clause) and [DELETE](https://orm.drizzle.team/docs/delete#with-delete-clause) statements
Usage examples
```ts
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:
```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:
- [with insert docs](https://orm.drizzle.team/docs/insert#with-insert-clause)
- [with update docs](https://orm.drizzle.team/docs/update#with-update-clause)
- [with delete docs](https://orm.drizzle.team/docs/delete#with-delete-clause)
### 🎉 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
```ts
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
```ts
await migrate(db, {
migrationsFolder: './drizzle',
migrationsSchema: 'custom',
});
```
### 🎉 SQLite Proxy batch 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](https://orm.drizzle.team/docs/batch-api)
You will need to specify a specific callback for batch queries and handle requests to proxy server:
```ts
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
+42
View File
@@ -0,0 +1,42 @@
## 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`.
```ts
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](http://orm.drizzle.team/docs/column-types/pg#timestamp)
## Bug fixed in this release
- [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
+23
View File
@@ -0,0 +1,23 @@
## New Features
### 🎉 OP-SQLite driver Support
Usage Example
```ts
import { open } from '@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](http://orm.drizzle.team/docs/get-started-sqlite#op-sqlite)
### Bug fixes
- Migration hook fixed for Expo driver
+17
View File
@@ -0,0 +1,17 @@
## New Features
### 🎉 `.if()` function added to all WHERE expressions
#### Select all users after cursors if a cursor value was provided
```ts
function getUsersAfter(cursor?: number) {
return db.select().from(users).where(
gt(users.id, cursor).if(cursor)
);
}
```
## Bug Fixes
- Fixed internal mappings for sessions `.all`, `.values`, `.execute` functions in AWS DataAPI
+9
View File
@@ -0,0 +1,9 @@
## Improvements
LibSQL migrations have been updated to utilize batch execution instead of transactions. As stated in the [documentation](https://docs.turso.tech/sdk/ts/reference#batch-transactions), 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
- [Sqlite] Fix findFirst query for bun:sqlite #1885 - thanks @shaileshaanand
+3
View File
@@ -0,0 +1,3 @@
- 🎉 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
+25
View File
@@ -0,0 +1,25 @@
## New Features
### 🎉 xata-http driver support
According their **[official website](https://xata.io)**, 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](https://xata.io/docs/postgres) on how to enable it in your account.
Drizzle ORM natively supports both the `xata` driver with `drizzle-orm/xata` package and the **[`postgres`](#postgresjs)** or **[`pg`](#node-postgres)** drivers for accessing a Xata Postgres database.
The following example use the Xata generated client, which you obtain by running the [xata init](https://xata.io/docs/getting-started/installation) CLI command.
```bash
pnpm add drizzle-orm @xata.io/client
```
```ts
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
+25
View File
@@ -0,0 +1,25 @@
## 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`.
```ts
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!
+27
View File
@@ -0,0 +1,27 @@
## 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
```ts
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:
- [Attempting to refresh a materialised view throws error](https://github.com/electric-sql/pglite/issues/63)
- [Attempting to SET TIME ZONE throws error](https://github.com/electric-sql/pglite/issues/62)
+10
View File
@@ -0,0 +1,10 @@
- 🎉 Added custom schema support to enums in Postgres:
```ts
import { pgSchema } from 'drizzle-orm/pg-core';
const mySchema = pgSchema('mySchema');
const colors = mySchema.enum('colors', ['red', 'green', 'blue']);
```
- 🐛 Split `where` clause in Postgres `.onConflictDoUpdate` method into `setWhere` and `targetWhere` clauses, to support both `where` cases in `on conflict ...` clause (#1628, #1302)
- 🐛 Fix query generation for `where` clause in Postgres `.onConflictDoNothing` method, as it was placed in a wrong spot (#1628)
+4
View File
@@ -0,0 +1,4 @@
## Bug fixes
- Add mappings for `@vercel/postgres` package
- Fix interval mapping for `neon` drivers - #1542
+16
View File
@@ -0,0 +1,16 @@
- 🎉 Added custom schema support to enums in Postgres (fixes #669 via #2048):
```ts
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!
+3
View File
@@ -0,0 +1,3 @@
- 🐛 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`
+140
View File
@@ -0,0 +1,140 @@
## 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.
```ts
// 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
```ts
// 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
```ts
// 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
```ts
// 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:
```ts
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
```ts
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
```ts
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!
```
- 🛠️ Fixed RQB behavior for tables with same names in different schemas
+324
View File
@@ -0,0 +1,324 @@
## Breaking changes
> Note: `drizzle-orm@0.31.0` can be used with `drizzle-kit@0.22.0` 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](#drizzle-kit-updates-drizzle-kit0220)
### 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.
```ts
// 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
```ts
// 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
```ts
// 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
```ts
// 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:
```ts
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
```ts
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
```ts
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](https://www.postgresql.org/docs/current/datatype-geometric.html)
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
```ts
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.
```ts
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:
```ts
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: `drizzle-kit@0.22.0`
> Release notes here are partially duplicated from [drizzle-kit@0.22.0]()
## 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
```ts
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
```ts
import { defineConfig } from 'drizzle-kit'
export default defaultConfig({
dialect: "postgresql",
dbCredentials: {
ssl: true, //"require" | "allow" | "prefer" | "verify-full" | options from node:tls
}
})
```
```ts
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
```ts
export const users = sqliteTable(
'users',
{
id: integer('id').primaryKey(),
email: text('email').notNull(),
},
(table) => ({
emailUniqueIndex: uniqueIndex('emailUniqueIndex').on(sql`lower(${table.email})`),
}),
);
```
```sql
-- 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](https://github.com/drizzle-team/drizzle-orm/issues/2341)
- Drizzle Studio: Error: Connection terminated unexpectedly - [#435](https://github.com/drizzle-team/drizzle-kit-mirror/issues/435)
- Unable to run sqlite migrations local - [#432](https://github.com/drizzle-team/drizzle-kit-mirror/issues/432)
- error: unknown option '--config' - [#423](https://github.com/drizzle-team/drizzle-kit-mirror/issues/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
```ts
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.
+33
View File
@@ -0,0 +1,33 @@
# New Features
## Live Queries 🎉
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:
```tsx
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');
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`
+10
View File
@@ -0,0 +1,10 @@
- 🎉 Added support for TiDB Cloud Serverless driver:
```ts
import { connect } from '@tidbcloud/serverless';
import { drizzle } from 'drizzle-orm/tidb-serverless';
const client = connect({ url: '...' });
const db = drizzle(client);
await db.select().from(...);
```
+17
View File
@@ -0,0 +1,17 @@
### 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
```ts
import { PrismaClient } from '@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
+1
View File
@@ -0,0 +1 @@
- Mark prisma clients package as optional - thanks @Cherry
+184
View File
@@ -0,0 +1,184 @@
# Preview release for `drizzle-orm@0.32.0` and `drizzle-kit@0.23.0`
> 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
### 🎉 PostgreSQL Sequences
You can now specify sequences in Postgres within any schema you need and define all the available properties
##### **Example**
```ts
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](https://wiki.postgresql.org/wiki/Don%27t_Do_This#Don.27t_use_serial): 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**
```ts
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](https://www.postgresql.org/docs/current/sql-createtable.html#SQL-CREATETABLE-PARMS-GENERATED-IDENTITY).
### 🎉 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
```ts
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`
```ts
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](https://dev.mysql.com/doc/refman/8.4/en/create-table-generated-columns.html)
Also MySQL has a few limitation for such columns usage, which is described [here](https://dev.mysql.com/doc/refman/8.4/en/alter-table-generated-columns.html)
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**
```ts
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](https://www.sqlite.org/gencol.html)
Also SQLite has a few limitation for such columns usage, which is described [here](https://www.sqlite.org/gencol.html)
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
```ts
import { defineConfig } from "drizzle-kit";
export default defineConfig({
dialect: "postgresql",
migrations: {
prefix: 'supabase'
}
});
```
+220
View File
@@ -0,0 +1,220 @@
# Release notes for `drizzle-orm@0.32.0` and `drizzle-kit@0.23.0`
> 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
```ts
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
```ts
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**
```ts
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](https://wiki.postgresql.org/wiki/Don%27t_Do_This#Don.27t_use_serial): 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**
```ts
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](https://www.postgresql.org/docs/current/sql-createtable.html#SQL-CREATETABLE-PARMS-GENERATED-IDENTITY).
### 🎉 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
```ts
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`
```ts
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](https://dev.mysql.com/doc/refman/8.4/en/create-table-generated-columns.html)
Also MySQL has a few limitation for such columns usage, which is described [here](https://dev.mysql.com/doc/refman/8.4/en/alter-table-generated-columns.html)
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**
```ts
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](https://www.sqlite.org/gencol.html)
Also SQLite has a few limitation for such columns usage, which is described [here](https://www.sqlite.org/gencol.html)
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
```ts
import { defineConfig } from "drizzle-kit";
export default defineConfig({
dialect: "postgresql",
migrations: {
prefix: 'supabase'
}
});
```
+5
View File
@@ -0,0 +1,5 @@
- 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](https://github.com/drizzle-team/drizzle-orm/issues/2011) - thanks @sillvva!
- Make inArray and notInArray accept empty list, closes [#1295](https://github.com/drizzle-team/drizzle-orm/issues/1295) - thanks @RemiPeruto!
- fix typo in lt typedoc - thanks @dalechyn!
- fix wrong example in README.md - thanks @7flash!
+4
View File
@@ -0,0 +1,4 @@
- Fix AWS Data API type hints bugs in RQB
- Fix set transactions in MySQL bug - thanks @roguesherlock
- Add forwaring dependencies within useLiveQuery, fixes [#2651](https://github.com/drizzle-team/drizzle-orm/issues/2651) - thanks @anstapol
- Export additional types from SQLite package, like `AnySQLiteUpdate` - thanks @veloii
+64
View File
@@ -0,0 +1,64 @@
## Breaking changes (for some of postgres.js users)
#### Bugs fixed for this breaking change
- [Open
[BUG]: jsonb always inserted as a json string when using postgres-js](https://github.com/drizzle-team/drizzle-orm/issues/724)
- [[BUG]: jsonb type on postgres implement incorrectly](https://github.com/drizzle-team/drizzle-orm/issues/1511)
> 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:**
```sql
update table_name
set jsonb_column = (jsonb_column #>> '{}')::jsonb;
```
**if you are using json:**
```sql
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:**
```sql
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:**
```sql
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
- [[BUG]: boolean mode not working with prepared statements (bettersqlite)](https://github.com/drizzle-team/drizzle-orm/issues/2568) - thanks @veloii
- [[BUG]: isTable helper function is not working](https://github.com/drizzle-team/drizzle-orm/issues/2672) - thanks @hajek-raven
- [[BUG]: Documentation is outdated on inArray and notInArray Methods](https://github.com/drizzle-team/drizzle-orm/issues/2690) - thanks @RemiPeruto

Some files were not shown because too many files have changed in this diff Show More