Drizzle uses schema definitions to describe the structure of the database. A schema is a collection of tables, columns, and relationships. In TypeScript, you can define a schema using Drizzle’s API. Each table is represented as a class, and columns are defined as properties of that class.
import { sqliteTable, text, integer } from 'drizzle-orm/sqlite-core';
// Define a users table
export const users = sqliteTable('users', {
id: integer('id').primaryKey(),
name: text('name').notNull(),
email: text('email').notNull().unique()
});
Drizzle provides a query builder API that allows you to construct SQL queries in a type - safe way. You can use methods like select
, insert
, update
, and delete
to perform various database operations.
One of the key features of Drizzle is its type safety. When you define a schema, Drizzle generates types based on the schema definition. This means that when you write queries, TypeScript can catch type - related errors at compile - time.
First, you need to install Drizzle and its related drivers. For SQLite, you can use the following commands:
npm install drizzle-orm sqlite3
import { drizzle } from 'drizzle-orm/sqlite-core';
import sqlite3 from 'sqlite3';
import { Database } from 'sqlite3';
// Create a SQLite database instance
const sqlite = new Database('example.db');
// Initialize Drizzle with the database instance
const db = drizzle(sqlite);
import { db, users } from './db';
async function getUsers() {
const allUsers = await db.select().from(users);
console.log(allUsers);
}
getUsers();
import { db, users } from './db';
async function insertUser() {
const newUser = await db.insert(users).values({
name: 'John Doe',
email: '[email protected]'
}).returning();
console.log(newUser);
}
insertUser();
It’s a good practice to organize your schema files in a separate directory. For example, you can create a schema
directory and put all your table definitions there.
src/
├── schema/
│ ├── users.ts
│ ├── posts.ts
└── index.ts
When working with database queries, it’s important to handle errors properly. You can use try - catch blocks to handle errors that occur during database operations.
async function getUsers() {
try {
const allUsers = await db.select().from(users);
console.log(allUsers);
} catch (error) {
console.error('Error fetching users:', error);
}
}
Transactions are useful when you need to perform multiple database operations as a single unit. If one operation fails, all the other operations in the transaction can be rolled back.
async function transferMoney() {
await db.transaction(async (tx) => {
try {
// Deduct money from one account
await tx.update(accounts).set({ balance: accounts.balance - 100 }).where(accounts.id.eq(1));
// Add money to another account
await tx.update(accounts).set({ balance: accounts.balance + 100 }).where(accounts.id.eq(2));
} catch (error) {
// Rollback the transaction if an error occurs
tx.rollback();
console.error('Transaction failed:', error);
}
});
}
For tables with large datasets, it’s a good idea to add indexes to columns that are frequently used in WHERE
clauses. In Drizzle, you can define indexes in your schema.
import { sqliteTable, text, integer, index } from 'drizzle-orm/sqlite-core';
export const posts = sqliteTable('posts', {
id: integer('id').primaryKey(),
title: text('title').notNull(),
authorId: integer('author_id').notNull()
}, (table) => {
return {
authorIndex: index('author_index').on(table.authorId)
};
});
Drizzle TypeScript is a powerful and flexible tool for working with databases in a type - safe way. By understanding its fundamental concepts, usage methods, common practices, and best practices, developers can write more reliable and maintainable database code. Whether you are building a small project or a large - scale application, Drizzle can help you streamline your database interactions and reduce the number of bugs in your code.