Releases: drizzle-team/drizzle-orm
[email protected]
- Fix SingleStore generate migrations command
0.37.0
New Dialects
🎉 SingleStore
dialect is now available in Drizzle
Thanks to the SingleStore team for creating a PR with all the necessary changes to support the MySQL-compatible part of SingleStore. You can already start using it with Drizzle. The SingleStore team will also help us iterate through updates and make more SingleStore-specific features available in Drizzle
import { int, singlestoreTable, varchar } from 'drizzle-orm/singlestore-core';
import { drizzle } from 'drizzle-orm/singlestore';
export const usersTable = singlestoreTable('users_table', {
id: int().primaryKey(),
name: varchar({ length: 255 }).notNull(),
age: int().notNull(),
email: varchar({ length: 255 }).notNull().unique(),
});
...
const db = drizzle(process.env.DATABASE_URL!);
db.select()...
You can check out our Getting started guides to try SingleStore!
New Drivers
🎉 SQLite Durable Objects
driver is now available in Drizzle
You can now query SQLite Durable Objects in Drizzle!
For the full example, please check our Get Started Section
/// <reference types="@cloudflare/workers-types" />
import { drizzle, DrizzleSqliteDODatabase } from 'drizzle-orm/durable-sqlite';
import { DurableObject } from 'cloudflare:workers'
import { migrate } from 'drizzle-orm/durable-sqlite/migrator';
import migrations from '../drizzle/migrations';
import { usersTable } from './db/schema';
export class MyDurableObject1 extends DurableObject {
storage: DurableObjectStorage;
db: DrizzleSqliteDODatabase<any>;
constructor(ctx: DurableObjectState, env: Env) {
super(ctx, env);
this.storage = ctx.storage;
this.db = drizzle(this.storage, { logger: false });
}
async migrate() {
migrate(this.db, migrations);
}
async insert(user: typeof usersTable.$inferInsert) {
await this.db.insert(usersTable).values(user);
}
async select() {
return this.db.select().from(usersTable);
}
}
export default {
/**
* This is the standard fetch handler for a Cloudflare Worker
*
* @param request - The request submitted to the Worker from the client
* @param env - The interface to reference bindings declared in wrangler.toml
* @param ctx - The execution context of the Worker
* @returns The response to be sent back to the client
*/
async fetch(request: Request, env: Env): Promise<Response> {
const id: DurableObjectId = env.MY_DURABLE_OBJECT1.idFromName('durable-object');
const stub = env.MY_DURABLE_OBJECT1.get(id);
await stub.migrate();
await stub.insert({
name: 'John',
age: 30,
email: '[email protected]',
})
console.log('New user created!')
const users = await stub.select();
console.log('Getting all users from the database: ', users)
return new Response();
}
}
Bug fixes
[email protected]
New Dialects
🎉 SingleStore
dialect is now available in Drizzle
Thanks to the SingleStore team for creating a PR with all the necessary changes to support the MySQL-compatible part of SingleStore. You can already start using it with Drizzle. The SingleStore team will also help us iterate through updates and make more SingleStore-specific features available in Drizzle
import 'dotenv/config';
import { defineConfig } from 'drizzle-kit';
export default defineConfig({
dialect: 'singlestore',
out: './drizzle',
schema: './src/db/schema.ts',
dbCredentials: {
url: process.env.DATABASE_URL!,
},
});
You can check out our Getting started guides to try SingleStore!
New Drivers
🎉 SQLite Durable Objects
driver is now available in Drizzle
You can now query SQLite Durable Objects in Drizzle!
For the full example, please check our Get Started Section
import 'dotenv/config';
import { defineConfig } from 'drizzle-kit';
export default defineConfig({
out: './drizzle',
schema: './src/db/schema.ts',
dialect: 'sqlite',
driver: 'durable-sqlite',
});
0.36.4
New Package: drizzle-seed
Note
drizzle-seed
can only be used with [email protected]
or higher. Versions lower than this may work at runtime but could have type issues and identity column issues, as this patch was introduced in [email protected]
Full Reference
The full API reference and package overview can be found in our official documentation
Basic Usage
In this example we will create 10 users with random names and ids
import { pgTable, integer, text } from "drizzle-orm/pg-core";
import { drizzle } from "drizzle-orm/node-postgres";
import { seed } from "drizzle-seed";
const users = pgTable("users", {
id: integer().primaryKey(),
name: text().notNull(),
});
async function main() {
const db = drizzle(process.env.DATABASE_URL!);
await seed(db, { users });
}
main();
Options
count
By default, the seed
function will create 10 entities.
However, if you need more for your tests, you can specify this in the seed options object
await seed(db, schema, { count: 1000 });
seed
If you need a seed to generate a different set of values for all subsequent runs, you can define a different number
in the seed
option. Any new number will generate a unique set of values
await seed(db, schema, { seed: 12345 });
The full API reference and package overview can be found in our official documentation
Features
Added OVERRIDING SYSTEM VALUE
api to db.insert()
If you want to force you own values for GENERATED ALWAYS AS IDENTITY
columns, you can use OVERRIDING SYSTEM VALUE
As PostgreSQL docs mentions
In an INSERT command, if ALWAYS is selected, a user-specified value is only accepted if the INSERT statement specifies OVERRIDING SYSTEM VALUE. If BY DEFAULT is selected, then the user-specified value takes precedence
await db.insert(identityColumnsTable).overridingSystemValue().values([
{ alwaysAsIdentity: 2 },
]);
Added .$withAuth()
API for Neon HTTP driver
Using this API, Drizzle will send you an auth token to authorize your query. It can be used with any query available in Drizzle by simply adding .$withAuth()
before it. This token will be used for a specific query
Examples
const token = 'HdncFj1Nm'
await db.$withAuth(token).select().from(usersTable);
await db.$withAuth(token).update(usersTable).set({ name: 'CHANGED' }).where(eq(usersTable.name, 'TARGET'))
Bug Fixes
0.36.3
New Features
Support for UPDATE ... FROM
in PostgreSQL and SQLite
As the SQLite documentation mentions:
Note
The UPDATE-FROM idea is an extension to SQL that allows an UPDATE statement to be driven by other tables in the database.
The "target" table is the specific table that is being updated. With UPDATE-FROM you can join the target table
against other tables in the database in order to help compute which rows need updating and what
the new values should be on those rows
Similarly, the PostgreSQL documentation states:
Note
A table expression allowing columns from other tables to appear in the WHERE condition and update expressions
Drizzle also supports this feature starting from this version
For example, current query:
await db
.update(users)
.set({ cityId: cities.id })
.from(cities)
.where(and(eq(cities.name, 'Seattle'), eq(users.name, 'John')))
Will generate this sql
update "users" set "city_id" = "cities"."id"
from "cities"
where ("cities"."name" = $1 and "users"."name" = $2)
-- params: [ 'Seattle', 'John' ]
You can also alias tables that are joined (in PG, you can also alias the updating table too).
const c = alias(cities, 'c');
await db
.update(users)
.set({ cityId: c.id })
.from(c);
Will generate this sql
update "users" set "city_id" = "c"."id"
from "cities" "c"
In PostgreSQL, you can also return columns from the joined tables.
const updatedUsers = await db
.update(users)
.set({ cityId: cities.id })
.from(cities)
.returning({ id: users.id, cityName: cities.name });
Will generate this sql
update "users" set "city_id" = "cities"."id"
from "cities"
returning "users"."id", "cities"."name"
Support for INSERT INTO ... SELECT
in all dialects
As the SQLite documentation mentions:
Note
The second form of the INSERT statement contains a SELECT statement instead of a VALUES clause.
A new entry is inserted into the table for each row of data returned by executing the SELECT statement.
If a column-list is specified, the number of columns in the result of the SELECT must be the same as
the number of items in the column-list. Otherwise, if no column-list is specified, the number of
columns in the result of the SELECT must be the same as the number of columns in the table.
Any SELECT statement, including compound SELECTs and SELECT statements with ORDER BY and/or LIMIT clauses,
may be used in an INSERT statement of this form.
Caution
To avoid a parsing ambiguity, the SELECT statement should always contain a WHERE clause, even if that clause is simply "WHERE true", if the upsert-clause is present. Without the WHERE clause, the parser does not know if the token "ON" is part of a join constraint on the SELECT, or the beginning of the upsert-clause.
As the PostgreSQL documentation mentions:
Note
A query (SELECT statement) that supplies the rows to be inserted
And as the MySQL documentation mentions:
Note
With INSERT ... SELECT, you can quickly insert many rows into a table from the result of a SELECT statement, which can select from one or many tables
Drizzle supports the current syntax for all dialects, and all of them share the same syntax. Let's review some common scenarios and API usage.
There are several ways to use select inside insert statements, allowing you to choose your preferred approach:
- You can pass a query builder inside the select function.
- You can use a query builder inside a callback.
- You can pass an SQL template tag with any custom select query you want to use
Query Builder
const insertedEmployees = await db
.insert(employees)
.select(
db.select({ name: users.name }).from(users).where(eq(users.role, 'employee'))
)
.returning({
id: employees.id,
name: employees.name
});
const qb = new QueryBuilder();
await db.insert(employees).select(
qb.select({ name: users.name }).from(users).where(eq(users.role, 'employee'))
);
Callback
await db.insert(employees).select(
() => db.select({ name: users.name }).from(users).where(eq(users.role, 'employee'))
);
await db.insert(employees).select(
(qb) => qb.select({ name: users.name }).from(users).where(eq(users.role, 'employee'))
);
SQL template tag
await db.insert(employees).select(
sql`select "users"."name" as "name" from "users" where "users"."role" = 'employee'`
);
await db.insert(employees).select(
() => sql`select "users"."name" as "name" from "users" where "users"."role" = 'employee'`
);
0.36.2
New Features
Bug and typo fixes
-
Fixed typos in repository: thanks @armandsalle, @masto, @wackbyte, @Asher-JH, @MaxLeiter
-
[MySQL] Correct $returningId() implementation to correctly store selected fields
[email protected]
Bug fixes
- Fixed typos in repository: thanks @armandsalle, @masto, @wackbyte, @Asher-JH, @MaxLeiter
- fix: wrong dialect set in mysql/sqlite introspect
0.36.1
Bug Fixes
- [BUG]: Using sql.placeholder with limit and/or offset for a prepared statement produces TS error - thanks @L-Mario564
- [BUG] If a query I am trying to modify with a dynamic query (....$dynamic()) contains any placeholders, I'm getting an error that says No value for placeholder.... provided - thanks @L-Mario564
- [BUG]: Error thrown when trying to insert an array of new rows using generatedAlwaysAsIdentity() for the id column - thanks @L-Mario564
- [BUG]: Unable to Use BigInt Types with Bun and Drizzle - thanks @L-Mario564
[email protected]
Improvements
- Added an OHM static imports checker to identify unexpected imports within a chain of imports in the drizzle-kit repo. For example, it checks if drizzle-orm is imported before drizzle-kit and verifies if the drizzle-orm import is available in your project.
- Adding more columns to Supabase auth.users table schema - thanks @nicholasdly
Bug Fixes
- [BUG]: [drizzle-kit]: Fix breakpoints option cannot be disabled - thanks @klotztech
- [BUG]: drizzle-kit introspect: SMALLINT import missing and incorrect DECIMAL UNSIGNED handling - thanks @L-Mario564
- Unsigned tinyints preventing migrations - thanks @L-Mario564
- [BUG]: Can't parse float(8,2) from database (precision and scale and/or unsigned breaks float types) - thanks @L-Mario564
- [BUG]: PgEnum generated migration doesn't escape single quotes - thanks @L-Mario564
- [BUG]: single quote not escaped correctly in migration file - thanks @L-Mario564
- [BUG]: Migrations does not escape single quotes - thanks @L-Mario564
- [BUG]: Issue with quoted default string values - thanks @L-Mario564
- [BUG]: SQl commands in wrong roder - thanks @L-Mario564
- [BUG]: Time with precision in drizzle-orm/pg-core adds double-quotes around type - thanks @L-Mario564
- [BUG]: Postgres push fails due to lack of quotes - thanks @L-Mario564
- [BUG]: TypeError: Cannot read properties of undefined (reading 'compositePrimaryKeys') - thanks @L-Mario564
- [BUG]: drizzle-kit introspect generates CURRENT_TIMESTAMP without sql operator on date column - thanks @L-Mario564
- [BUG]: Drizzle-kit introspect doesn't pull correct defautl statement - thanks @L-Mario564
- [BUG]: Problem on MacBook - This statement does not return data. Use run() instead - thanks @L-Mario564
- [BUG]: Enum column names that are used as arrays are not quoted - thanks @L-Mario564
- [BUG]: drizzle-kit generate ignores index operators - thanks @L-Mario564
- dialect param config error message is wrong - thanks @L-Mario564
- [BUG]: Error setting default enum field values - thanks @L-Mario564
- [BUG]: drizzle-kit does not respect the order of columns configured in primaryKey() - thanks @L-Mario564
- [BUG]: Cannot drop Unique Constraint MySQL - thanks @L-Mario564
[email protected]
- Fix [BUG]: Undefined properties when using drizzle-kit push
- Fix TypeError: Cannot read properties of undefined (reading 'isRLSEnabled')
- Fix push bugs, when pushing a schema with linked policy to a table from
drizzle-orm/supabase