Skip to content

Commit

Permalink
Merge pull request #159 from drizzle-team/planetscale-serverless
Browse files Browse the repository at this point in the history
Add support for PlanetScale serverless driver
  • Loading branch information
AndriiSherman authored Feb 3, 2023
2 parents 3da5e14 + 20754d5 commit a371248
Show file tree
Hide file tree
Showing 22 changed files with 993 additions and 88 deletions.
19 changes: 19 additions & 0 deletions changelogs/drizzle-orm/0.17.5.md
Original file line number Diff line number Diff line change
@@ -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);
```
9 changes: 7 additions & 2 deletions drizzle-orm/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "drizzle-orm",
"version": "0.17.4",
"version": "0.17.5",
"description": "Drizzle ORM package for SQL databases",
"scripts": {
"build": "tsc && resolve-tspaths && cp ../README.md package.json dist/",
Expand Down Expand Up @@ -33,6 +33,7 @@
},
"homepage": "https://github.com/drizzle-team/drizzle-orm#readme",
"peerDependencies": {
"@aws-sdk/client-rds-data": ">=3 <4",
"@cloudflare/workers-types": ">=3",
"@neondatabase/serverless": ">=0.1 <0.2",
"@types/better-sqlite3": "*",
Expand All @@ -45,7 +46,7 @@
"postgres": ">=3 <4",
"sql.js": ">=1 <2",
"sqlite3": ">=5 <6",
"@aws-sdk/client-rds-data": ">=3 <4"
"@planetscale/database": ">=1 <2"
},
"peerDependenciesMeta": {
"mysql2": {
Expand Down Expand Up @@ -86,12 +87,16 @@
},
"@aws-sdk/client-rds-data": {
"optional": true
},
"@planetscale/database": {
"optional": true
}
},
"devDependencies": {
"@aws-sdk/client-rds-data": "^3.257.0",
"@cloudflare/workers-types": "^3.18.0",
"@neondatabase/serverless": "^0.1.13",
"@planetscale/database": "^1.5.0",
"@types/better-sqlite3": "^7.6.2",
"@types/node": "^18.11.9",
"@types/pg": "^8.6.5",
Expand Down
103 changes: 68 additions & 35 deletions drizzle-orm/src/mysql-core/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,11 @@

Drizzle ORM is a TypeScript ORM for SQL databases designed with maximum type safety in mind. It comes with a [drizzle-kit](https://github.com/drizzle-team/drizzle-kit-mirror) CLI companion for automatic SQL migrations generation. This is the documentation for Drizzle ORM version for PostgreSQL.

| Driver | Support |
| :- | :-: |
| [mysql2](https://github.com/sidorares/node-mysql2) ||
| [Planetscale Serverless](https://github.com/planetscale/database-js) ||

## Installation

```bash
Expand Down Expand Up @@ -78,9 +83,9 @@ import { users } from './schema';

// create the connection
const poolConnection = mysql.createPool({
host:'localhost',
user: 'root',
database: 'test'
host: 'localhost',
user: 'root',
database: 'test',
});

const db = drizzle(poolConnection);
Expand All @@ -99,9 +104,30 @@ import { users } from './schema';

// create the connection
const connection = await mysql.createConnection({
host:'localhost',
user: 'root',
database: 'test'
host: 'localhost',
user: 'root',
database: 'test',
});

const db = drizzle(connection);

const allUsers = await db.select(users);
```

### Connect using PlanetScale Serverless client

```typescript
// db.ts
import { drizzle } from 'drizzle-orm/planetscale-serverless';

import { connect } from '@planetscale/database';
import { users } from './schema';

// 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);
Expand All @@ -115,21 +141,28 @@ This is how you declare SQL schema in `schema.ts`. You can declare tables, index

```typescript
// db.ts
import { int, mysqlEnum, mysqlTable, serial, uniqueIndex, varchar } from 'drizzle-orm/mysql-core';
import {
int,
mysqlEnum,
mysqlTable,
serial,
uniqueIndex,
varchar,
} from 'drizzle-orm/mysql-core';

// declaring enum in database
export const countries = mysqlTable('countries', {
id: serial('id').primaryKey(),
name: varchar('name', { length: 256 }),
id: serial('id').primaryKey(),
name: varchar('name', { length: 256 }),
}, (countries) => ({
nameIndex: uniqueIndex('name_idx').on(countries.name),
nameIndex: uniqueIndex('name_idx').on(countries.name),
}));

export const cities = mysqlTable('cities', {
id: serial('id').primaryKey(),
name: varchar('name', { length: 256 }),
countryId: int('country_id').references(() => countries.id),
popularity: mysqlEnum('popularity', ['unknown', 'known', 'popular']),
id: serial('id').primaryKey(),
name: varchar('name', { length: 256 }),
countryId: int('country_id').references(() => countries.id),
popularity: mysqlEnum('popularity', ['unknown', 'known', 'popular']),
});
```

Expand Down Expand Up @@ -278,23 +311,22 @@ Usage example
```typescript
// Table in default schema
const publicUsersTable = mysqlTable('users', {
id: serial('id').primaryKey(),
name: text('name').notNull(),
verified: boolean('verified').notNull().default(false),
jsonb: json<string[]>('jsonb'),
createdAt: timestamp('created_at', { fsp: 2 }).notNull().defaultNow(),
id: serial('id').primaryKey(),
name: text('name').notNull(),
verified: boolean('verified').notNull().default(false),
jsonb: json<string[]>('jsonb'),
createdAt: timestamp('created_at', { fsp: 2 }).notNull().defaultNow(),
});


// Table in custom schema
const mySchema = mysqlSchema('mySchema');

const mySchemaUsersTable = mySchema('users', {
id: serial('id').primaryKey(),
name: text('name').notNull(),
verified: boolean('verified').notNull().default(false),
jsonb: json<string[]>('jsonb'),
createdAt: timestamp('created_at', { fsp: 2 }).notNull().defaultNow(),
id: serial('id').primaryKey(),
name: text('name').notNull(),
verified: boolean('verified').notNull().default(false),
jsonb: json<string[]>('jsonb'),
createdAt: timestamp('created_at', { fsp: 2 }).notNull().defaultNow(),
});
```

Expand Down Expand Up @@ -440,7 +472,7 @@ await db.insert(users).values(...newUsers);
await db.update(users)
.set({ name: 'Mr. Dan' })
.where(eq(users.name, 'Dan'));

await db.delete(users)
.where(eq(users.name, 'Dan'));
```
Expand All @@ -460,7 +492,7 @@ const cities = mysqlTable('cities', {
const users = mysqlTable('users', {
id: serial('id').primaryKey(),
name: text('name'),
cityId: int('city_id').references(() => cities.id)
cityId: int('city_id').references(() => cities.id),
});

const result = db.select(cities)
Expand Down Expand Up @@ -517,7 +549,7 @@ const result = await db.select(files)
const result1 = await db.select(cities).fields({
userId: users.id,
cityId: cities.id,
cityName: cities.name
cityName: cities.name,
}).leftJoin(users, eq(users.cityId, cities.id));

// Select all fields from users and only id and name from cities
Expand All @@ -526,12 +558,11 @@ const result2 = await db.select(cities).fields({
user: users,
city: {
id: cities.id,
name: cities.name
name: cities.name,
},
}).leftJoin(users, eq(users.cityId, cities.id));
```


## Prepared statements

```typescript
Expand Down Expand Up @@ -560,7 +591,9 @@ If you have some complex queries to execute and drizzle-orm can't handle them ye

```typescript
// it will automatically run a parametrized query!
const res: MySqlQueryResult<{ id: number; name: string; }> = await db.execute<{ id: number, name: string }>(sql`select * from ${users} where ${users.id} = ${userId}`);
const res: MySqlQueryResult<{ id: number; name: string }> = await db.execute<
{ id: number; name: string }
>(sql`select * from ${users} where ${users.id} = ${userId}`);
```

## Migrations
Expand Down Expand Up @@ -619,13 +652,13 @@ import mysql from 'mysql2/promise';

// create the connection
const poolConnection = mysql.createPool({
host:'localhost',
user: 'root',
database: 'test'
host: 'localhost',
user: 'root',
database: 'test',
});

const db = drizzle(poolConnection);

// this will automatically run needed migrations on the database
await migrate(db, { migrationsFolder: './drizzle' })
await migrate(db, { migrationsFolder: './drizzle' });
```
14 changes: 7 additions & 7 deletions drizzle-orm/src/mysql-core/db.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,36 +2,36 @@ import { ResultSetHeader } from 'mysql2/promise';
import { SQLWrapper } from '~/sql';
import { MySqlDialect } from './dialect';
import { MySqlDelete, MySqlInsertBuilder, MySqlSelect, MySqlUpdateBuilder } from './query-builders';
import { MySqlQueryResult, MySqlSession } from './session';
import { MySqlSession, QueryResultHKT, QueryResultKind } from './session';
import { AnyMySqlTable, MySqlTable } from './table';
import { orderSelectedFields } from './utils';

export class MySqlDatabase {
export class MySqlDatabase<TQueryResult extends QueryResultHKT, TSession extends MySqlSession> {
constructor(
/** @internal */
readonly dialect: MySqlDialect,
/** @internal */
readonly session: MySqlSession,
readonly session: TSession,
) {}

select<TTable extends AnyMySqlTable>(from: TTable): MySqlSelect<TTable> {
const fields = orderSelectedFields(from[MySqlTable.Symbol.Columns]);
return new MySqlSelect(from, fields, this.session, this.dialect);
}

update<TTable extends AnyMySqlTable>(table: TTable): MySqlUpdateBuilder<TTable> {
update<TTable extends AnyMySqlTable>(table: TTable): MySqlUpdateBuilder<TTable,TQueryResult> {
return new MySqlUpdateBuilder(table, this.session, this.dialect);
}

insert<TTable extends AnyMySqlTable>(table: TTable): MySqlInsertBuilder<TTable> {
insert<TTable extends AnyMySqlTable>(table: TTable): MySqlInsertBuilder<TTable,TQueryResult> {
return new MySqlInsertBuilder(table, this.session, this.dialect);
}

delete<TTable extends AnyMySqlTable>(table: TTable): MySqlDelete<TTable> {
delete<TTable extends AnyMySqlTable>(table: TTable): MySqlDelete<TTable, TQueryResult> {
return new MySqlDelete(table, this.session, this.dialect);
}

execute<T extends { [column: string]: any } = ResultSetHeader>(query: SQLWrapper): Promise<MySqlQueryResult<T>> {
execute<T extends { [column: string]: any } = ResultSetHeader>(query: SQLWrapper): Promise<QueryResultKind<TQueryResult, T>> {
return this.session.execute(query.getSQL());
}
}
4 changes: 0 additions & 4 deletions drizzle-orm/src/mysql-core/dialect.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,10 +56,6 @@ export class MySqlDialect {
}
}

createDB(session: MySqlSession): MySqlDatabase {
return new MySqlDatabase(this, session);
}

escapeName(name: string): string {
return `\`${name}\``;
}
Expand Down
12 changes: 7 additions & 5 deletions drizzle-orm/src/mysql-core/query-builders/delete.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { MySqlDialect } from '~/mysql-core/dialect';
import { SelectFieldsOrdered } from '~/mysql-core/operations';
import { MySqlRawQueryResult, MySqlSession, PreparedQuery, PreparedQueryConfig } from '~/mysql-core/session';
import { MySqlSession, PreparedQuery, PreparedQueryConfig, QueryResultHKT, QueryResultKind } from '~/mysql-core/session';
import { AnyMySqlTable } from '~/mysql-core/table';
import { QueryPromise } from '~/query-promise';
import { Query, SQL, SQLWrapper } from '~/sql';
Expand All @@ -13,13 +13,15 @@ export interface MySqlDeleteConfig {

export interface MySqlDelete<
TTable extends AnyMySqlTable,
TQueryResult extends QueryResultHKT,
TReturning = undefined,
> extends QueryPromise<MySqlRawQueryResult> {}
> extends QueryPromise<QueryResultKind<TQueryResult, never> > {}

export class MySqlDelete<
TTable extends AnyMySqlTable,
TQueryResult extends QueryResultHKT,
TReturning = undefined,
> extends QueryPromise<MySqlRawQueryResult> implements SQLWrapper {
> extends QueryPromise<QueryResultKind<TQueryResult, never> > implements SQLWrapper {
private config: MySqlDeleteConfig;

constructor(
Expand Down Expand Up @@ -61,15 +63,15 @@ export class MySqlDelete<

private _prepare(name?: string): PreparedQuery<
PreparedQueryConfig & {
execute: MySqlRawQueryResult;
execute: TQueryResult;
}
> {
return this.session.prepareQuery(this.dialect.sqlToQuery(this.getSQL()), this.config.returning, name);
}

prepare(name: string): PreparedQuery<
PreparedQueryConfig & {
execute: MySqlRawQueryResult;
execute: QueryResultKind<TQueryResult, never>;
}
> {
return this._prepare(name);
Expand Down
Loading

0 comments on commit a371248

Please sign in to comment.