0.16.2 • Published 1 year ago

drizzle-orm-mysql v0.16.2

Weekly downloads
-
License
Apache-2.0
Repository
github
Last release
1 year ago

Drizzle ORM is a TypeScript ORM for SQL databases designed with maximum type safety in mind. It comes with a drizzle-kit CLI companion for automatic SQL migrations generation. This is the documentation for Drizzle ORM version for PostgreSQL.

Installation

# npm
npm i drizzle-orm drizzle-orm-mysql mysql2
npm i -D @types/pg
npm i -D drizzle-kit

# yarn
yarn add drizzle-orm drizzle-orm-mysql mysql2
yarn add -D @types/pg
yarn add -D drizzle-kit

# pnpm
pnpm add drizzle-orm drizzle-orm-mysql2 mysql2
pnpm add -D @types/pg
pnpm add -D drizzle-kit

SQL schema declaration

With drizzle-orm you declare SQL schema in TypeScript. You can have either one schema.ts file with all declarations or you can group them logically in multiple files. We prefer to use single file schema.

Single schema file example

📦 <project root>
 └ 📂 src
    └ 📂 db
       └ 📜schema.ts

Multiple schema files example

📦 <project root>
 └ 📂 src
    └ 📂 db
       └ 📂 schema
          ├ 📜users.ts
          ├ 📜countries.ts
          ├ 📜cities.ts
          ├ 📜products.ts
          ├ 📜clients.ts
          ├ 📜enums.ts
          └ 📜etc.ts

Quick start

// schema.ts
export const users = mysqlTable('users', {
  id: serial('id').primaryKey(),
  fullName: text('full_name'),
  phone: varchar('phone', { length: 256 }),
});

Connect using mysql2 Pool (recommended)

// db.ts
import { drizzle } from 'drizzle-orm-mysql/mysql2';

import mysql from 'mysql2/promise';
import { users } from './schema';

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

const db = drizzle(poolConnection);

const allUsers = await db.select(users);

Connect using mysql2 Client

// db.ts
import { drizzle } from 'drizzle-orm-mysql/mysql2';

import mysql from 'mysql2/promise';
import { users } from './schema';

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

const db = drizzle(connection);

const allUsers = await db.select(users);

Schema declaration

This is how you declare SQL schema in schema.ts. You can declare tables, indexes and constraints, foreign keys and enums. Please pay attention to export keyword, they are mandatory if you'll be using drizzle-kit SQL migrations generator.

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

// declaring enum in database
export const popularityEnum = mysqlEnum('popularity', ['unknown', 'known', 'popular']);

export const countries = mysqlTable('countries', {
	id: serial('id').primaryKey(),
	name: varchar('name', { length: 256 }),
}, (countries) => ({
	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: popularityEnum('popularity'),
});

Database and table entity types

// db.ts
import { InferModel, MySqlDatabase, MySqlRawQueryResult, mysqlTable, serial, text, varchar } from 'drizzle-orm-mysql';
import mysql from 'mysql2/promise';
import { drizzle } from 'drizzle-orm-mysql/mysql2';

const users = mysqlTable('users', {
  id: serial('id').primaryKey(),
  fullName: text('full_name'),
  phone: varchar('phone', { length: 256 }),
});

export type User = InferModel<typeof users>; // return type when queried
export type NewUser = InferModel<typeof users, 'insert'>; // insert type
...

// init node-postgres Pool or Client
const poolConnection = mysql.createPool({
    host:'localhost', 
    user: 'root',
    database: 'test'
});

export const db: MySqlDatabase = drizzle(poolConnection);

const result: User[] = await db.select(users);

/* type MySqlRawQueryExample is a response from mysql2 driver
   type MySqlRawQueryResult = [ResultSetHeader, FieldPacket[]];
   type ResultSetHeader = {
      affectedRows: number;
      fieldCount: number;
      info: string;
      insertId: number;
      serverStatus: number;
      warningStatus: number;
      changedRows?: number;
    }
*/
export async function insertUser(user: NewUser): Promise<MySqlRawQueryResult> {
  return db.insert(users).values(user);
}

Declaring indexes and foreign keys

// db.ts
import { foreignKey, index, int, mysqlTable, serial, uniqueIndex, varchar } from 'drizzle-orm-mysql';

export const countries = mysqlTable('countries', {
    id: serial('id').primaryKey(),
    name: varchar('name', { length: 256 }),
    population: int('population'),
  }, (table) => ({
    nameIdx: index('name_idx').on(table.name), // one column
    namePopulationIdx: index('name_population_idx').on(table.name, table.population), // multiple columns
    uniqueIdx: uniqueIndex('unique_idx').on(table.name), // unique index
  })
);

export const cities = mysqlTable('cities', {
  id: serial('id').primaryKey(),
  name: varchar('name', { length: 256 }),
  countryId: int('country_id').references(() => countries.id), // inline foreign key
  countryName: varchar('country_id', { length: 256 }),
}, (cities) => ({
  // explicit foreign key with 1 column
  countryFk: foreignKey(() => ({
    columns: [cities.countryId],
    foreignColumns: [countries.id],
  })),
  // explicit foreign key with multiple columns
  countryIdNameFk: foreignKey(() => ({
    columns: [cities.countryId, cities.countryName],
    foreignColumns: [countries.id, countries.name],
  })),
}));

// Index declaration reference
index('name_idx')
    .on(table.column1, table.column2, ...)
    .using('btree' | 'hash')
    .lock('default' | 'none' | 'shared' | 'exclusive')
    .algorythm('default' | 'inplace' | 'copy')

---here I left---

Column types

export const popularityEnum = mysqlEnum('popularity', ['unknown', 'known', 'popular']);
popularityEnum('column_name');

int('...');
tinyint('name');
smallint('name');
mediumint('name');
bigint('...', { mode: 'number' });

real('name', { precision: 1, scale: 1 });
decimal('name', { precision: 1, scale: 1 });
double('name', { precision: 1, scale: 1 });
float('name',);

serial('name');

binary('name');
varbinary('name', { length: 2 });

char('name');
varchar('name', { length: 2 });
text('name');

boolean('name');

date('...');
datetime('...', { mode: 'date' | 'string', fsp: 0..6 });
time('...', { mode: 'date' | 'string', fsp: 0..6 });
year('...');

timestamp('name');
timestamp('...', { mode: 'date' | 'string', fsp: 0..6 })
timestamp('...').defaultNow()

json('name');
json<string[]>('name');

Select, Insert, Update, Delete

Select

Querying, sorting and filtering. We also support partial select.

...
import { mysqlTable, serial, text, varchar } from 'drizzle-orm-mysql';
import { drizzle } from 'drizzle-orm-mysql/mysql2';
import { and, asc, desc, eq, or } from 'drizzle-orm/expressions';

const users = mysqlTable('users', {
  id: serial('id').primaryKey(),
  name: text('full_name'),
});

const db = drizzle(...);

await db.select(users);
await db.select(users).where(eq(users.id, 42));

// you can combine filters with eq(...) or or(...)
await db.select(users)
  .where(and(eq(users.id, 42), eq(users.name, 'Dan')));

await db.select(users)
  .where(or(eq(users.id, 42), eq(users.id, 1)));

// partial select
const result = await db.select(users).fields({
    mapped1: users.id,
    mapped2: users.name,
  });
const { mapped1, mapped2 } = result[0];

// limit, offset & order by
await db.select(users).limit(10).offset(10);
await db.select(users).orderBy(asc(users.name));
await db.select(users).orderBy(desc(users.name));
// you can pass multiple order args
await db.select(users).orderBy(asc(users.name), desc(users.name));

// list of all filter operators
eq(column, value)
eq(column1, column2)
ne(column, value)
ne(column1, column2)

notEq(column, value)
less(column, value)
lessEq(column, value)

gt(column, value)
gt(column1, column2)
gte(column, value)
gte(column1, column2)
lt(column, value)
lt(column1, column2)
lte(column, value)
lte(column1, column2)

isNull(column)
isNotNull(column)

inArray(column, values[])
inArray(column, sqlSubquery)
notInArray(column, values[])
notInArray(column, sqlSubquery)

exists(sqlSubquery)
notExists(sqlSubquery)

between(column, min, max)
notBetween(column, min, max)

like(column, value)
like(column, value)
ilike(column, value)
notIlike(column, value)

not(sqlExpression)

and(expressions: SQL[])
or(expressions: SQL[])

Insert

import { mysqlTable, serial, text, timestamp, InferModel } from 'drizzle-orm-mysql';
import { drizzle } from 'drizzle-orm-mysql/mysql2';

const users = mysqlTable('users', {
  id: serial('id').primaryKey(),
  name: text('name'),
  createdAt: timestamp('created_at'),
});

type NewUser = InferModel<typeof users>;

const db = drizzle(...);

await db.insert(users)
  .values({
    name: 'Andrew',
    createdAt: new Date(),
  });

// accepts vararg of items
await db.insert(users)
  .values(
    {
      name: 'Andrew',
      createdAt: new Date(),
    },
    {
      name: 'Dan',
      createdAt: new Date(),
    },
  );

const newUsers: NewUser[] = [
  {
      name: 'Andrew',
      createdAt: new Date(),
  },
  {
    name: 'Dan',
    createdAt: new Date(),
  },
];

await db.insert(users).values(...newUsers);

Update and Delete

await db.update(users)
  .set({ name: 'Mr. Dan' })
  .where(eq(users.name, 'Dan'));
	
await db.delete(users)
  .where(eq(users.name, 'Dan'));

Joins

Last but not least. Probably the most powerful feature in the library🚀

Many-to-one

const cities = mysqlTable('cities', {
  id: serial('id').primaryKey(),
  name: text('name'),
});

const users = mysqlTable('users', {
  id: serial('id').primaryKey(),
  name: text('name'),
  cityId: int('city_id').references(() => cities.id)
});

const result = db.select(cities)
  .leftJoin(users, eq(cities2.id, users2.cityId));

Many-to-many

const users = mysqlTable('users', {
  id: serial('id').primaryKey(),
  name: text('name'),
});

const chatGroups = mysqlTable('chat_groups', {
  id: serial('id').primaryKey(),
  name: text('name'),
});

const usersToChatGroups = mysqlTable('usersToChatGroups', {
  userId: integer('user_id').notNull().references(() => users.id),
  groupId: integer('group_id').notNull().references(() => chatGroups.id),
});

// querying user group with id 1 and all the participants(users)
const result = await db.select(usersToChatGroups)
  .leftJoin(users, eq(usersToChatGroups.userId, users.id))
  .leftJoin(chatGroups, eq(usersToChatGroups.groupId, chatGroups.id))
  .where(eq(chatGroups.id, 1));

Join aliases and self-joins

import { ..., alias } from 'drizzle-orm-mysql';

export const files = mysqlTable('folders', {
  name: text('name').notNull(),
  parent: text('parent_folder')
})

const nestedFiles = alias(files, 'nested_files');

// will return files and folders and nested files for each folder at root dir
const result = await db.select(files)
  .leftJoin(nestedFiles, eq(files.name, nestedFiles.name))
  .where(eq(files.parent, '/'));

Join using partial select

// Select user ID and city ID and name
const result1 = await db.select(cities).fields({
  userId: users.id,
  cityId: cities.id,
  cityName: cities.name
}).leftJoin(users, eq(users.cityId, cities.id));

// Select all fields from users and only id and name from cities
const result2 = await db.select(cities).fields({
  // Supports any level of nesting!
  user: users,
  city: {
    id: cities.id,
    name: cities.name
  },
}).leftJoin(users, eq(users.cityId, cities.id));

Prepared statements

const query = db.select(users)
  .where(eq(users.name, 'Dan'))
  .prepare();

const result = await query.execute();

Prepared statements with parameters

import { placeholder } from 'drizzle-orm-mysql';

const query = db.select(users)
  .where(eq(users.name, placeholder('name')))
  .prepare();

const result = await query.execute({ name: 'Dan' });

Raw queries execution

If you have some complex queries to execute and drizzle-orm can't handle them yet, you can use the db.execute method to execute raw queries.

// 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}`);

Migrations

Automatic SQL migrations generation with drizzle-kit

DrizzleKit - is a CLI migrator tool for DrizzleORM. It is probably one and only tool that lets you completely automatically generate SQL migrations and covers ~95% of the common cases like deletions and renames by prompting user input.

Check out the docs for DrizzleKit

For schema file:

import { index, integer, mysqlTable, serial, varchar } from 'drizzle-orm-mysql';

export const users = mysqlTable('users', {
  id: serial('id').primaryKey(),
  fullName: varchar('full_name', { length: 256 }),
}, (users) => ({
  nameIdx: index('name_idx').on(users.fullName),
}));

export const authOtps = mysqlTable('auth_otp', {
  id: serial('id').primaryKey(),
  phone: varchar('phone', { length: 256 }),
  userId: int('user_id').references(() => users.id),
}

It will generate:

And you can run migrations manually or using our embedded migrations module

import { drizzle } from 'drizzle-orm-mysql/mysql2';
import { migrate } from 'drizzle-orm-mysql/mysql2/migrator';
import mysql from 'mysql2/promise';

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

const db = drizzle(poolConnection);

// this will automatically run needed migrations on the database
await migrate(db, { migrationsFolder: './drizzle' })
0.15.0-2e1e5b2

1 year ago

0.15.3-0dcbb16

1 year ago

0.15.1-6879c1d

1 year ago

0.16.1-97f9977

1 year ago

0.16.0-b9e9ba0

1 year ago

0.15.0-60954a3

1 year ago

0.15.3-1e62a3e

1 year ago

0.15.0-7d17618

1 year ago

0.15.1-9728cc6

1 year ago

0.16.1-2c4c5b1

1 year ago

0.15.3-844cb31

1 year ago

0.15.1-2b4d90d

1 year ago

0.15.3-1f6c448

1 year ago

0.14.3-59f0a3a

1 year ago

0.15.3-72fb2c0

1 year ago

0.16.2-60d4ce6

1 year ago

0.15.3-98b2097

1 year ago

0.15.3-adba448

1 year ago

0.16.1-b4b5a09

1 year ago

0.15.1-656bcc3

1 year ago

0.14.3

1 year ago

0.15.3-335d188

1 year ago

0.16.0-11f7ff3

1 year ago

0.16.0-af45b90

1 year ago

0.15.3-71be15e

1 year ago

0.15.1-a1b76f5

1 year ago

0.15.3-b422bc1

1 year ago

0.15.1-80901ff

1 year ago

0.15.3-1c43305

1 year ago

0.15.1-f67dd9d

1 year ago

0.16.1-cf5a510

1 year ago

0.16.0-51c77ba

1 year ago

0.15.0-88523f9

1 year ago

0.15.0

1 year ago

0.15.1

1 year ago

0.15.2

1 year ago

0.15.3

1 year ago

0.15.3-d8f67aa

1 year ago

0.16.1-c522f26

1 year ago

0.15.3-c675dde

1 year ago

0.16.0-484a8ae

1 year ago

0.16.1-ddf4681

1 year ago

0.16.2-78fb61e

1 year ago

0.15.3-36368e7

1 year ago

0.15.3-f77c6c2

1 year ago

0.15.3-b3dd40c

1 year ago

0.15.2-52e75f5

1 year ago

0.16.0

1 year ago

0.16.1

1 year ago

0.16.2

1 year ago

0.15.1-19c5c02

1 year ago

0.16.1-56d16f9

1 year ago

0.15.1-3548c99

1 year ago

0.15.1-1766537

1 year ago

0.16.0-4124cf0

1 year ago

0.16.0-3e17d6e

1 year ago

0.15.3-30915c1

1 year ago

0.15.3-23baedd

1 year ago

0.16.1-43776eb

1 year ago

0.15.3-bbe577c

1 year ago

0.15.1-4a5b2e3

1 year ago

0.14.2-f8d0d46

1 year ago

0.14.2-dd27c86

1 year ago

0.14.2-6f226c1

1 year ago

0.14.2-cce4cab

1 year ago

0.15.0-a90d3bc

1 year ago

0.14.2-e295848

1 year ago

0.14.1-f617bb6

1 year ago

0.14.2-5b14ef4

1 year ago

0.14.2-3793d78

1 year ago

0.14.2-1bcee50

1 year ago

0.14.1-1c58471

1 year ago

0.14.2-01c3d82

1 year ago

0.14.2-e902ba8

1 year ago

0.14.2-5514014

1 year ago

0.14.2-9ba6169

1 year ago

0.14.2-1e42665

1 year ago

0.14.2

1 year ago

0.14.2-314c1fa

1 year ago

0.14.2-4e3a5b9

1 year ago

0.14.2-c153bbf

1 year ago

0.14.2-67805d4

1 year ago

0.14.1-c5dca58

1 year ago

0.15.0-07f606f

1 year ago

0.14.2-c7344a5

1 year ago

0.14.2-4eada6d

1 year ago

0.14.2-3967f06

1 year ago

0.14.2-a52eacc

1 year ago

0.14.2-cc06fec

1 year ago

0.14.2-5ce7d69

1 year ago

0.14.1-1d98f11

1 year ago

0.12.0-beta.9

2 years ago

0.12.0-beta.8

2 years ago

0.12.0-beta.7

2 years ago

0.12.0-beta.6

2 years ago

0.12.0-beta.5

2 years ago

0.12.0-beta.4

2 years ago

0.12.0-beta.12

2 years ago

0.12.0-beta.10

2 years ago

0.12.0-beta.14

2 years ago

0.12.0-beta.13

2 years ago

0.12.0-beta.3

2 years ago

0.12.0-beta.2

2 years ago

0.12.0-beta.1

2 years ago

0.12.0-beta.0

2 years ago