Skip to content

Commit

Permalink
Merge pull request #1468 from drizzle-team/fix-imports
Browse files Browse the repository at this point in the history
Fix imports
  • Loading branch information
AndriiSherman authored Nov 5, 2023
2 parents 1a482ce + 99ce577 commit 0a8127c
Show file tree
Hide file tree
Showing 125 changed files with 713 additions and 452 deletions.
259 changes: 222 additions & 37 deletions changelogs/drizzle-orm/0.29.0.md
Original file line number Diff line number Diff line change
@@ -1,28 +1,213 @@
## New Features

### MySQL `unsigned` option for bigint
### 🎉 MySQL `unsigned` option for bigint

You can now specify `bigint unsigned` type

```ts
const table = mysqlTable('table', {
id: bigint('id', { mode: 'number', unsigned: true }),
id: bigint('id', { mode: 'number', unsigned: true }),
});
```

### Improved query builder types
### 🎉 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
.select()
.from(users)
.where(eq(users.id, 1))
.where(eq(users.name, 'John')); // ❌ Type error - where() can only be invoked once
```

### Possibility to specify name for primary keys and foreign keys
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);
```

### 🎉 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 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

### 🎉 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

Expand All @@ -32,42 +217,42 @@ 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,
),
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;
}[],
{
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;
}[],
];
```

Expand Down
4 changes: 2 additions & 2 deletions drizzle-orm/src/alias.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@ import type { AnyColumn } from './column.ts';
import { Column } from './column.ts';
import { entityKind, is } from './entity.ts';
import type { Relation } from './relations.ts';
import { SQL, sql } from './sql/index.ts';
import type { View} from './sql/sql.ts';
import { SQL, sql } from './sql/sql.ts';
import { Table } from './table.ts';
import { ViewBaseConfig } from './view-common.ts';
import type { View } from './view.ts';

export class ColumnAliasProxyHandler<TColumn extends Column> implements ProxyHandler<TColumn> {
static readonly [entityKind]: string = 'ColumnAliasProxyHandler';
Expand Down
2 changes: 1 addition & 1 deletion drizzle-orm/src/aws-data-api/common/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import type { Field } from '@aws-sdk/client-rds-data';
import { TypeHint } from '@aws-sdk/client-rds-data';
import type { QueryTypingsValue } from '~/sql/index.ts';
import type { QueryTypingsValue } from '~/sql/sql.ts';

export function getValueFromDataApi(field: Field) {
if (field.stringValue !== undefined) {
Expand Down
2 changes: 1 addition & 1 deletion drizzle-orm/src/aws-data-api/pg/session.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import {
} from '~/pg-core/index.ts';
import type { SelectedFieldsOrdered } from '~/pg-core/query-builders/select.types.ts';
import type { RelationalSchemaConfig, TablesRelationalConfig } from '~/relations.ts';
import { fillPlaceholders, type QueryTypingsValue, type QueryWithTypings, type SQL, sql } from '~/sql/index.ts';
import { fillPlaceholders, type QueryTypingsValue, type QueryWithTypings, type SQL, sql } from '~/sql/sql.ts';
import { mapResultRow } from '~/utils.ts';
import { getValueFromDataApi, toValueParam } from '../common/index.ts';

Expand Down
2 changes: 1 addition & 1 deletion drizzle-orm/src/better-sqlite3/session.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { entityKind } from '~/entity.ts';
import type { Logger } from '~/logger.ts';
import { NoopLogger } from '~/logger.ts';
import type { RelationalSchemaConfig, TablesRelationalConfig } from '~/relations.ts';
import { fillPlaceholders, type Query, sql } from '~/sql/index.ts';
import { fillPlaceholders, type Query, sql } from '~/sql/sql.ts';
import type { SQLiteSyncDialect } from '~/sqlite-core/dialect.ts';
import { SQLiteTransaction } from '~/sqlite-core/index.ts';
import type { SelectedFieldsOrdered } from '~/sqlite-core/query-builders/select.types.ts';
Expand Down
2 changes: 1 addition & 1 deletion drizzle-orm/src/bun-sqlite/session.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { entityKind } from '~/entity.ts';
import type { Logger } from '~/logger.ts';
import { NoopLogger } from '~/logger.ts';
import type { RelationalSchemaConfig, TablesRelationalConfig } from '~/relations.ts';
import { fillPlaceholders, type Query, sql } from '~/sql/index.ts';
import { fillPlaceholders, type Query, sql } from '~/sql/sql.ts';
import type { SQLiteSyncDialect } from '~/sqlite-core/dialect.ts';
import { SQLiteTransaction } from '~/sqlite-core/index.ts';
import type { SelectedFieldsOrdered } from '~/sqlite-core/query-builders/select.types.ts';
Expand Down
2 changes: 1 addition & 1 deletion drizzle-orm/src/column-builder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { entityKind } from '~/entity.ts';
import type { Column } from './column.ts';
import type { MySqlColumn } from './mysql-core/index.ts';
import type { PgColumn } from './pg-core/index.ts';
import type { SQL } from './sql/index.ts';
import type { SQL } from './sql/sql.ts';
import type { SQLiteColumn } from './sqlite-core/index.ts';
import type { Simplify } from './utils.ts';

Expand Down
2 changes: 1 addition & 1 deletion drizzle-orm/src/column.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, ColumnDataType } from './column-builder.ts';
import { entityKind } from './entity.ts';
import type { DriverValueMapper, SQL, SQLWrapper } from './sql/index.ts';
import type { DriverValueMapper, SQL, SQLWrapper } from './sql/sql.ts';
import type { Table } from './table.ts';
import type { Update } from './utils.ts';

Expand Down
3 changes: 1 addition & 2 deletions drizzle-orm/src/d1/session.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,7 @@ import type { Logger } from '~/logger.ts';
import { NoopLogger } from '~/logger.ts';
import type { RelationalSchemaConfig, TablesRelationalConfig } from '~/relations.ts';
import type { PreparedQuery } from '~/session.ts';
import { type Query, sql } from '~/sql/index.ts';
import { fillPlaceholders } from '~/sql/index.ts';
import { type Query, sql, fillPlaceholders } from '~/sql/sql.ts';
import type { SQLiteAsyncDialect } from '~/sqlite-core/dialect.ts';
import { SQLiteTransaction } from '~/sqlite-core/index.ts';
import type { SelectedFieldsOrdered } from '~/sqlite-core/query-builders/select.types.ts';
Expand Down
1 change: 0 additions & 1 deletion drizzle-orm/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,3 @@ export * from './subquery.ts';
export * from './table.ts';
export * from './utils.ts';
export * from './view-common.ts';
export * from './view.ts';
2 changes: 1 addition & 1 deletion drizzle-orm/src/libsql/session.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import type { Logger } from '~/logger.ts';
import { NoopLogger } from '~/logger.ts';
import type { RelationalSchemaConfig, TablesRelationalConfig } from '~/relations.ts';
import type { PreparedQuery } from '~/session.ts';
import { fillPlaceholders, type Query, sql } from '~/sql/index.ts';
import { fillPlaceholders, type Query, sql } from '~/sql/sql.ts';
import type { SQLiteAsyncDialect } from '~/sqlite-core/dialect.ts';
import { SQLiteTransaction } from '~/sqlite-core/index.ts';
import type { SelectedFieldsOrdered } from '~/sqlite-core/query-builders/select.types.ts';
Expand Down
2 changes: 1 addition & 1 deletion drizzle-orm/src/mysql-core/alias.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { TableAliasProxyHandler } from '~/alias.ts';
import type { BuildAliasTable } from './query-builders/select.types.ts';
import type { MySqlTable } from './table.ts';
import type { MySqlViewBase } from './view.ts';
import type { MySqlViewBase } from './view-base.ts';

export function alias<TTable extends MySqlTable | MySqlViewBase, TAlias extends string>(
table: TTable,
Expand Down
2 changes: 1 addition & 1 deletion drizzle-orm/src/mysql-core/checks.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { entityKind } from '~/entity.ts';
import type { SQL } from '~/sql/index.ts';
import type { SQL } from '~/sql/sql.ts';
import type { MySqlTable } from './table.ts';

export class CheckBuilder {
Expand Down
Loading

0 comments on commit 0a8127c

Please sign in to comment.