# Drizzle

> Drizzle is a modern TypeScript ORM developers wanna use in their next project. It is lightweight at only ~7.4kb minified+gzipped, and it's tree shakeable with exactly 0 dependencies. It supports every PostgreSQL, MySQL, SQLite and SingleStore database and is serverless-ready by design.

Source: https://orm.drizzle.team/docs/arktype

import Npm from '@mdx/Npm.astro';
import Callout from '@mdx/Callout.astro';

<Callout type="error">
Starting from `drizzle-orm@1.0.0-beta.15`, `drizzle-arktype` has been deprecated in favor of first-class schema generation support within Drizzle ORM itself

You can still use `drizzle-arktype` package but all new update will be added to Drizzle ORM directly
</Callout>

# arktype

### Install the dependencies

<Npm>
arktype
</Npm>

### Select schema

Defines the shape of data queried from the database - can be used to validate API responses.

```ts copy
import { pgTable, text, integer } from 'drizzle-orm/pg-core';
import { createSelectSchema } from 'drizzle-orm/arktype';

const users = pgTable('users', {
  id: integer().generatedAlwaysAsIdentity().primaryKey(),
  name: text().notNull(),
  age: integer().notNull()
});

const userSelectSchema = createSelectSchema(users);

const rows = await db.select({ id: users.id, name: users.name }).from(users).limit(1);
const parsed: { id: number; name: string; age: number } = userSelectSchema(rows[0]); // Error: `age` is not returned in the above query

const rows = await db.select().from(users).limit(1);
const parsed: { id: number; name: string; age: number } = userSelectSchema(rows[0]); // Will parse successfully
```

Views and enums are also supported.

```ts copy
import { pgEnum } from 'drizzle-orm/pg-core';
import { createSelectSchema } from 'drizzle-orm/arktype';

const roles = pgEnum('roles', ['admin', 'basic']);
const rolesSchema = createSelectSchema(roles);
const parsed: 'admin' | 'basic' = rolesSchema(...);

const usersView = pgView('users_view').as((qb) => qb.select().from(users).where(gt(users.age, 18)));
const usersViewSchema = createSelectSchema(usersView);
const parsed: { id: number; name: string; age: number } = usersViewSchema(...);
```

### Insert schema

Defines the shape of data to be inserted into the database - can be used to validate API requests.

```ts copy
import { pgTable, text, integer } from 'drizzle-orm/pg-core';
import { createInsertSchema } from 'drizzle-orm/arktype';

const users = pgTable('users', {
  id: integer().generatedAlwaysAsIdentity().primaryKey(),
  name: text().notNull(),
  age: integer().notNull()
});

const userInsertSchema = createInsertSchema(users);

const user = { name: 'John' };
const parsed: { name: string, age: number } = userInsertSchema(user); // Error: `age` is not defined

const user = { name: 'Jane', age: 30 };
const parsed: { name: string, age: number } = userInsertSchema(user); // Will parse successfully
await db.insert(users).values(parsed);
```

### Update schema

Defines the shape of data to be updated in the database - can be used to validate API requests.

```ts copy
import { pgTable, text, integer } from 'drizzle-orm/pg-core';
import { createUpdateSchema } from 'drizzle-orm/arktype';
import { parse } from 'arktype';

const users = pgTable('users', {
  id: integer().generatedAlwaysAsIdentity().primaryKey(),
  name: text().notNull(),
  age: integer().notNull()
});

const userUpdateSchema = createUpdateSchema(users);

const user = { id: 5, name: 'John' };
const parsed: { name?: string | undefined, age?: number | undefined } = userUpdateSchema(user); // Error: `id` is a generated column, it can't be updated

const user = { age: 35 };
const parsed: { name?: string | undefined, age?: number | undefined } = userUpdateSchema(user); // Will parse successfully
await db.update(users).set(parsed).where(eq(users.name, 'Jane'));
```

### Refinements

Each create schema function accepts an additional optional parameter that you can used to extend, modify or completely overwite a field's schema. Defining a callback function will extend or modify while providing a arktype schema will overwrite it.

```ts copy
import { pgTable, text, integer, json } from 'drizzle-orm/pg-core';
import { createSelectSchema } from 'drizzle-orm/arktype';
import { parse, pipe, maxLength, object, string } from 'arktype';

const users = pgTable('users', {
  id: integer().generatedAlwaysAsIdentity().primaryKey(),
  name: text().notNull(),
  bio: text(),
  preferences: json()
});

const userSelectSchema = createSelectSchema(users, {
  name: (schema) => pipe(schema, maxLength(20)), // Extends schema
  bio: (schema) => pipe(schema, maxLength(1000)), // Extends schema before becoming nullable/optional
  preferences: object({ theme: string() }) // Overwrites the field, including its nullability
});

const parsed: {
  id: number;
  name: string,
  bio?: string | undefined;
  preferences: {
    theme: string;
  };
} = userSelectSchema(...);
```

### Data type reference

```ts
pg.boolean();

mysql.boolean();

sqlite.integer({ mode: 'boolean' });

// Schema
type.boolean;
```

```ts
pg.date({ mode: 'date' });
pg.timestamp({ mode: 'date' });

mysql.date({ mode: 'date' });
mysql.datetime({ mode: 'date' });
mysql.timestamp({ mode: 'date' });

sqlite.integer({ mode: 'timestamp' });
sqlite.integer({ mode: 'timestamp_ms' });

// Schema
type.Date;
```

```ts
pg.date({ mode: 'string' });
pg.timestamp({ mode: 'string' });
pg.cidr();
pg.inet();
pg.interval();
pg.macaddr();
pg.macaddr8();
pg.numeric();
pg.text();
pg.sparsevec();
pg.time();

mysql.binary();
mysql.date({ mode: 'string' });
mysql.datetime({ mode: 'string' });
mysql.decimal();
mysql.time();
mysql.timestamp({ mode: 'string' });
mysql.varbinary();

sqlite.numeric();
sqlite.text({ mode: 'text' });

// Schema
type.string;
```

```ts
pg.bit({ dimensions: ... });

// Schema
type(`/^[01]{${column.dimensions}}$/`);
```

```ts
pg.uuid();

// Schema
type(/^[\da-f]{8}(?:-[\da-f]{4}){3}-[\da-f]{12}$/iu);
```

```ts
pg.char({ length: ... });

mysql.char({ length: ... });

// Schema
type.string.exactlyLength(length);
```

```ts
pg.varchar({ length: ... });

mysql.varchar({ length: ... });

sqlite.text({ mode: 'text', length: ... });

// Schema
type.string.atMostLength(length);
```

```ts
mysql.tinytext();

// Schema
type.string.atMostLength(255); // unsigned 8-bit integer limit
```

```ts
mysql.text();

// Schema
type.string.atMostLength(65_535); // unsigned 16-bit integer limit
```

```ts
mysql.mediumtext();

// Schema
type.string.atMostLength(16_777_215); // unsigned 24-bit integer limit
```

```ts
mysql.longtext();

// Schema
type.string.atMostLength(4_294_967_295); // unsigned 32-bit integer limit
```

```ts
pg.text({ enum: ... });
pg.char({ enum: ... });
pg.varchar({ enum: ... });

mysql.tinytext({ enum: ... });
mysql.mediumtext({ enum: ... });
mysql.text({ enum: ... });
mysql.longtext({ enum: ... });
mysql.char({ enum: ... });
mysql.varchar({ enum: ... });
mysql.mysqlEnum(..., ...);

sqlite.text({ mode: 'text', enum: ... });

// Schema
type.enumerated(...enum);
```

```ts
mysql.tinyint();

// Schema
type.keywords.number.integer.atLeast(-128).atMost(127); // 8-bit integer lower and upper limit
```

```ts
mysql.tinyint({ unsigned: true });

// Schema
type.keywords.number.integer.atLeast(0).atMost(255); // unsigned 8-bit integer lower and upper limit
```

```ts
pg.smallint();
pg.smallserial();

mysql.smallint();

// Schema
type.keywords.number.integer.atLeast(-32_768).atMost(32_767); // 16-bit integer lower and upper limit
```

```ts
mysql.smallint({ unsigned: true });

// Schema
type.keywords.number.integer.atLeast(0).atMost(65_535); // unsigned 16-bit integer lower and upper limit
```

```ts
pg.real();

mysql.float();

// Schema
type.number.atLeast(-8_388_608).atMost(8_388_607); // 24-bit integer lower and upper limit
```

```ts
mysql.mediumint();

// Schema
type.keywords.number.integer.atLeast(-8_388_608).atMost(8_388_607); // 24-bit integer lower and upper limit
```

```ts
mysql.float({ unsigned: true });

// Schema
type.number.atLeast(0).atMost(16_777_215); // unsigned 24-bit integer lower and upper limit
```

```ts
mysql.mediumint({ unsigned: true });

// Schema
type.keywords.number.integer.atLeast(0).atMost(16_777_215); // unsigned 24-bit integer lower and upper limit
```

```ts
pg.integer();
pg.serial();

mysql.int();

// Schema
type.keywords.number.integer.atLeast(-2_147_483_648).atMost(2_147_483_647); // 32-bit integer lower and upper limit
```

```ts
mysql.int({ unsigned: true });

// Schema
type.keywords.number.integer.atLeast(0).atMost(4_294_967_295); // unsgined 32-bit integer lower and upper limit
```

```ts
pg.doublePrecision();

mysql.double();
mysql.real();

sqlite.real();

// Schema
type.number.atLeast(-140_737_488_355_328).atMost(140_737_488_355_327); // 48-bit integer lower and upper limit
```

```ts
mysql.double({ unsigned: true });

// Schema
type.number.atLeast(0).atMost(281_474_976_710_655); // unsigned 48-bit integer lower and upper limit
```

```ts
pg.bigint({ mode: 'number' });
pg.bigserial({ mode: 'number' });

mysql.bigint({ mode: 'number' });
mysql.bigserial({ mode: 'number' });

sqlite.integer({ mode: 'number' });

// Schema
type.keywords.number.integer.atLeast(-9_007_199_254_740_991).atMost(9_007_199_254_740_991); // Javascript min. and max. safe integers
```

```ts
mysql.serial();

// Schema
type.keywords.number.integer.atLeast(0).atMost(9_007_199_254_740_991); // Javascript max. safe integer
```

```ts
pg.bigint({ mode: 'bigint' });
pg.bigserial({ mode: 'bigint' });

mysql.bigint({ mode: 'bigint' });

sqlite.blob({ mode: 'bigint' });

// Schema
type.bigint.narrow(
  (value, ctx) => value < -9_223_372_036_854_775_808n ? ctx.mustBe('greater than') : value > 9_223_372_036_854_775_807n ? ctx.mustBe('less than') : true
); // 64-bit integer lower and upper limit
```

```ts
mysql.bigint({ mode: 'bigint', unsigned: true });

// Schema
type.bigint.narrow(
  (value, ctx) => value < 0n ? ctx.mustBe('greater than') : value > 18_446_744_073_709_551_615n ? ctx.mustBe('less than') : true
); // unsigned 64-bit integer lower and upper limit
```

```ts
mysql.year();

// Schema
type.keywords.number.integer.atLeast(1_901).atMost(2_155);
```

```ts
pg.geometry({ type: 'point', mode: 'tuple' });
pg.point({ mode: 'tuple' });

// Schema
type([type.number, type.number]);
```

```ts
pg.geometry({ type: 'point', mode: 'xy' });
pg.point({ mode: 'xy' });

// Schema
type({ x: type.number, y: type.number });
```

```ts
pg.halfvec({ dimensions: ... });
pg.vector({ dimensions: ... });

// Schema
type.number.array().exactlyLength(dimensions);
```

```ts
pg.line({ mode: 'abc' });

// Schema
type({ a: type.number, b: type.number, c: type.number });
```

```ts
pg.line({ mode: 'tuple' });

// Schema
type([type.number, type.number, type.number]);
```

```ts
pg.json();
pg.jsonb();

mysql.json();

sqlite.blob({ mode: 'json' });
sqlite.text({ mode: 'json' });

// Schema
type('string | number | boolean | null').or(type('unknown.any[] | Record<string, unknown.any>'));
```

```ts
sqlite.blob({ mode: 'buffer' });

// Schema
type.instanceOf(Buffer);
```

```ts
pg.dataType().array(...);

// Schema
baseDataTypeSchema.array().exactlyLength(size);
```


Source: https://orm.drizzle.team/docs/cockroach/aliases

import Section from '@mdx/Section.astro';

# Aliases
Drizzle supports aliasing for tables, columns, subqueries and CTEs — mapping directly to the SQL `AS` keyword.

### Table aliasing
You can alias tables using the `alias` function. This is useful when you need to join the same table multiple times, 
for example in self-referencing relationships like employees and their managers:

<Section>
```ts copy {9}
import { alias, cockroachTable, int4, string } from "drizzle-orm/cockroach-core";

const employees = cockroachTable("employees", {
  id: int4().primaryKey(),
  name: string(),
  managerId: int4("manager_id"),
});

const manager = alias(employees, "manager");

await db.select({
  employeeName: employees.name,
  managerName: manager.name,
})
  .from(employees)
  .leftJoin(manager, eq(employees.managerId, manager.id));
```
```sql
select "employees"."name", "manager"."name"
from "employees"
left join "employees" as "manager" on "employees"."manager_id" = "manager"."id";
```
</Section>

### Column aliasing
You can alias columns using the `.as()` method on columns and `sql` expressions.
This maps directly to the SQL `AS` keyword and lets you control the name of a column in the query result:

<Section>
```ts {3}
const result = await db.select({
  id: users.id,
  lowerName: users.name.as("lower_name"),
}).from(users);
```
```sql
select "id", "name" as "lower_name" from "users";
```
</Section>

You can also use `.as()` with `sql` expressions:

<Section>
```ts {3}
const result = await db.select({
  id: users.id,
  lowerName: sql<string>`lower(${users.name})`.as("lower_name"),
}).from(users);
```
```sql
select "id", lower("name") as "lower_name" from "users";
```
</Section>

### Subquery aliasing
When using a subquery as a data source, you must provide an alias using `.as()`. 
This lets you reference the subquery's columns in the outer query:

<Section>
```ts
const sq = db.select().from(users).where(eq(users.id, 42)).as('sq');

const result = await db.select().from(sq);
```
```sql
select "id", "name", "age" from (select "id", "name", "age" from "users" where "users"."id" = 42) "sq";
```
</Section>

Subqueries can also be used in joins:

<Section>
```ts
const sq = db.select().from(users).where(eq(users.id, 42)).as('sq');

const result = await db.select().from(users).leftJoin(sq, eq(users.id, sq.id));
```
```sql
select "users"."id", "users"."name", "users"."age", "sq"."id", "sq"."name", "sq"."age"
  from "users"
  left join (select "id", "name", "age" from "users" where "users"."id" = 42) "sq"
    on "users"."id" = "sq"."id";
```
</Section>

### CTE aliasing
Common table expressions (CTEs) are aliased using `db.$with('alias')`. 
The alias name is used to reference the CTE in the main query:

<Section>
```ts
const sq = db.$with('sq').as(db.select().from(users).where(eq(users.id, 42)));

const result = await db.with(sq).select().from(sq);
```
```sql
with "sq" as (select "id", "name", "age" from "users" where "users"."id" = 42)
select "id", "name", "age" from "sq";
```
</Section>

When using `sql` expressions inside a CTE, you need to alias them with `.as()` to be able to reference them in the outer query:

<Section>
```ts
const sq = db.$with('sq').as(db.select({
  name: sql<string>`upper(${users.name})`.as('name'),
}).from(users));

const result = await db.with(sq).select({ name: sq.name }).from(sq);
```
```sql
with "sq" as (select upper("name") as "name" from "users")
select "name" from "sq";
```
</Section>

Source: https://orm.drizzle.team/docs/cockroach/arktype

import Npm from '@mdx/Npm.astro';
import Callout from '@mdx/Callout.astro';

# arktype

### Install the dependencies

<Npm>
arktype
</Npm>

### Select schema

Defines the shape of data queried from the database - can be used to validate API responses.

```ts copy
import { int4, cockroachTable, text } from 'drizzle-orm/cockroach-core';
import { createSelectSchema } from 'drizzle-orm/arktype';
import type { ArkErrors } from 'arktype';

const users = cockroachTable('users', {
  id: int4().primaryKey().generatedAlwaysAsIdentity(),
  name: text().notNull(),
  age: int4().notNull()
});

const userSelectSchema = createSelectSchema(users);

const rows = await db.select({ id: users.id, name: users.name }).from(users).limit(1);
const parsed: ArkErrors | { id: number; name: string; age: number } = userSelectSchema(rows[0]); // Error: `age` is not returned in the above query

const rows = await db.select().from(users).limit(1);
const parsed: ArkErrors | { id: number; name: string; age: number } = userSelectSchema(rows[0]); // Will parse successfully
```

Views and enums are also supported.

```ts copy
import { cockroachEnum, cockroachView } from 'drizzle-orm/cockroach-core';
import { gt } from 'drizzle-orm';
import { createSelectSchema } from 'drizzle-orm/arktype';
import type { ArkErrors } from 'arktype';

const roles = cockroachEnum('roles', ['admin', 'basic']);
const rolesSchema = createSelectSchema(roles);
const parsed: 'admin' | 'basic' = rolesSchema(...);

const usersView = cockroachView('users_view').as((qb) => qb.select().from(users).where(gt(users.age, 18)));
const usersViewSchema = createSelectSchema(usersView);
const parsed: ArkErrors | { id: number; name: string; age: number } = usersViewSchema(...);
```

### Insert schema

Defines the shape of data to be inserted into the database - can be used to validate API requests.

```ts copy
import { int4, cockroachTable, text } from 'drizzle-orm/cockroach-core';
import { createInsertSchema } from 'drizzle-orm/arktype';
import { ArkErrors } from "arktype";

const users = cockroachTable('users', {
  id: int4().primaryKey().generatedAlwaysAsIdentity(),
  name: text().notNull(),
  age: int4().notNull()
});

const userInsertSchema = createInsertSchema(users);

const user = { name: 'John' };
const parsed: ArkErrors | { name: string, age: number } = userInsertSchema(user); // Error: `age` is not defined

const user = { name: 'Jane', age: 30 };
const parsed: ArkErrors | { name: string, age: number } = userInsertSchema(user); // Will parse successfully

if (parsed instanceof ArkErrors) {
  console.error(parsed.summary);
  process.exit(1);
}

await db.insert(users).values(parsed);
```

### Update schema

Defines the shape of data to be updated in the database - can be used to validate API requests.

```ts copy
import { int4, cockroachTable, text } from 'drizzle-orm/cockroach-core';
import { createUpdateSchema } from 'drizzle-orm/arktype';
import { eq } from "drizzle-orm";
import { ArkErrors } from 'arktype';

const users = cockroachTable('users', {
  id: int4().primaryKey().generatedAlwaysAsIdentity(),
  name: text().notNull(),
  age: int4().notNull()
});

const userUpdateSchema = createUpdateSchema(users);

const user = { age: 35 };
const parsed: ArkErrors | { name?: string | undefined, age?: number | undefined } = userUpdateSchema(user); // Will parse successfully

if (parsed instanceof ArkErrors) {
  console.error(parsed.summary);
  process.exit(1);
}

await db.update(users).set(parsed).where(eq(users.name, 'Jane'));
```

### Refinements

Each create schema function accepts an additional optional parameter that you can used to extend, modify or completely overwite a field's schema. Defining a callback function will extend or modify while providing a arktype schema will overwrite it.

```ts copy
import { int4, jsonb, cockroachTable, text } from 'drizzle-orm/cockroach-core';
import { createSelectSchema } from 'drizzle-orm/arktype';
import { ArkErrors, type } from 'arktype';

const users = cockroachTable('users', {
  id: int4().primaryKey().generatedAlwaysAsIdentity(),
  name: text().notNull(),
  bio: text(),
  preferences: jsonb()
});

const userSelectSchema = createSelectSchema(users, {
  name: (schema) => schema.atMostLength(20), // Extends schema
  bio: () => type.string.atMostLength(2000), // Extends schema before becoming nullable/optional
  preferences: type({ theme: 'string' }) // Overwrites the field, including its nullability
});

const parsed: ArkErrors | {
  id: number;
  name: string,
  bio: string | null;
  preferences: {
    theme: string;
  };
} = userSelectSchema(...);
```

### Data type reference

CockroachDB data type mappings follow the CockroachDB column builders. See the [CockroachDB data types](/docs/cockroach/column-types) page for the full column reference.


Source: https://orm.drizzle.team/docs/cockroach/cache

import Callout from '@mdx/Callout.astro';
import Npm from '@mdx/Npm.astro';

# Cache

Drizzle sends every query straight to your database by default. There are no hidden actions, no automatic caching 
or invalidation - you'll always see exactly what runs. If you want caching, you must opt in.

By default, Drizzle uses a `explicit` caching strategy (i.e. `global: false`), so nothing is ever cached unless you ask. 
This prevents surprises or hidden performance traps in your application. 
Alternatively, you can flip on `all` caching (`global: true`) so that every select will look in cache first.

## Quickstart

### Upstash integration

Drizzle provides an `upstashCache()` helper out of the box. By default, this uses Upstash Redis with automatic configuration if environment variables are set.

```ts
import { upstashCache } from "drizzle-orm/cache/upstash";
import { drizzle } from "drizzle-orm/...";

const db = drizzle(process.env.DB_URL!, {
  cache: upstashCache({ token: process.env.UPSTASH_TOKEN, url: process.env.UPSTASH_URL }),
});
```

You can also explicitly define your Upstash credentials, enable global caching for all queries by default or pass custom caching options:

```ts
import { upstashCache } from "drizzle-orm/cache/upstash";
import { drizzle } from "drizzle-orm/...";

const db = drizzle(process.env.DB_URL!, {
  cache: upstashCache({
    // 👇 Redis credentials (optional — can also be pulled from env vars)
    url: '<UPSTASH_URL>',
    token: '<UPSTASH_TOKEN>',

    // 👇 Enable caching for all queries by default (optional)
    global: true,

    // 👇 Default cache behavior (optional)
    config: { ex: 60 }
  })
});
```

## Cache config reference

Drizzle supports the following cache config options for Upstash:

```ts
export type CacheConfig = {
  /**
   * Expiration in seconds (positive integer)
   */
  ex?: number;
  /**
   * Set an expiration (TTL or time to live) on one or more fields of a given hash key.
   * Used for HEXPIRE command
   */
  hexOptions?: "NX" | "nx" | "XX" | "xx" | "GT" | "gt" | "LT" | "lt";
};
```

## Cache usage examples

Once you've configured caching, here's how the cache behaves:

**Case 1: Drizzle with `global: false` (default, opt-in caching)**

```ts
import { upstashCache } from "drizzle-orm/cache/upstash";
import { drizzle } from "drizzle-orm/...";

const db = drizzle(process.env.DB_URL!, {
  // 👇 `global: true` is not passed, false by default
  cache: upstashCache({ url: "", token: "" }),
});
```

In this case, the following query won't read from cache

```ts
const res = await db.select().from(users);

// Any mutate operation will still trigger the cache's onMutate handler
// and attempt to invalidate any cached queries that involved the affected tables
await db.insert(users).value({ email: "cacheman@upstash.com" });
```

To make this query read from the cache, call `.$withCache()`

```ts
const res = await db.select().from(users).$withCache();
```

`.$withCache` has a set of options you can use to manage and configure this specific query strategy

```ts
// rewrite the config for this specific query
.$withCache({ config: {} })

// give this query a custom cache key (instead of hashing query+params under the hood)
.$withCache({ tag: 'custom_key' })

// turn off auto-invalidation for this query
// note: this leads to eventual consistency (explained below)
.$withCache({ autoInvalidate: false })
```

<Callout>
**Eventual consistency example**

This example is only relevant if you manually set `autoInvalidate: false`. By default, `autoInvalidate` is enabled. 

You might want to turn off `autoInvalidate` if:
- your data doesn't change often, and slight staleness is acceptable (e.g. product listings, blog posts)
- you handle cache invalidation manually

In those cases, turning it off can reduce unnecessary cache invalidation. However, in most cases, we recommend keeping the default enabled.

Example: Imagine you cache the following query on `usersTable` with a 3-second TTL:

``` ts
const recent = await db
  .select().from(usersTable)
  .$withCache({ config: { ex: 3 }, autoInvalidate: false });
```

If someone runs `db.insert(usersTable)...` the cache won't be invalidated immediately. For up to 3 seconds, you'll keep seeing the old data until it eventually becomes consistent.
</Callout>

**Case 2: Drizzle with `global: true` option**

```ts
import { upstashCache } from "drizzle-orm/cache/upstash";
import { drizzle } from "drizzle-orm/...";

const db = drizzle(process.env.DB_URL!, {
  cache: upstashCache({ url: "", token: "", global: true }),
});
```

In this case, the following query will read from cache

```ts
const res = await db.select().from(users);
```

If you want to disable cache for this specific query, call `.$withCache(false)`

```ts
// disable cache for this query
const res = await db.select().from(users).$withCache(false);
```

You can also use cache instance from a `db` to invalidate specific tables or tags

```ts
// Invalidate all queries that use the `users` table. You can do this with the Drizzle instance.
await db.$cache.invalidate({ tables: users });
// or
await db.$cache.invalidate({ tables: [users, posts] });

// Invalidate all queries that use the `usersTable`. You can do this by using just the table name.
await db.$cache.invalidate({ tables: "usersTable" });
// or
await db.$cache.invalidate({ tables: ["usersTable", "postsTable"] });

// You can also invalidate custom tags defined in any previously executed select queries.
await db.$cache.invalidate({ tags: "custom_key" });
// or
await db.$cache.invalidate({ tags: ["custom_key", "custom_key1"] });
```

## Custom cache

This example shows how to plug in a custom `cache` in Drizzle: you provide functions to fetch data from the cache, store results back into cache, and invalidate entries whenever a mutation runs.

Cache extension provides this set of config options
```ts
export type CacheConfig = {
  /** expire time, in seconds */
  ex?: number;
  /** expire time, in milliseconds */
  px?: number;
  /** Unix time (sec) at which the key will expire */
  exat?: number;
  /** Unix time (ms) at which the key will expire */
  pxat?: number;
  /** retain existing TTL when updating a key */
  keepTtl?: boolean;
  /** options for HEXPIRE (hash-field TTL) */
  hexOptions?: 'NX' | 'XX' | 'GT' | 'LT' | 'nx' | 'xx' | 'gt' | 'lt';
};
```

```ts
const db = drizzle(process.env.DB_URL!, { cache: new TestGlobalCache() });
```

```ts
import Keyv from "keyv";

export class TestGlobalCache extends Cache {
  private globalTtl: number = 1000;
  // This object will be used to store which query keys were used
  // for a specific table, so we can later use it for invalidation.
  private usedTablesPerKey: Record<string, string[]> = {};

  constructor(private kv: Keyv = new Keyv()) {
    super();
  }

  // For the strategy, we have two options:
  // - 'explicit': The cache is used only when .$withCache() is added to a query.
  // - 'all': All queries are cached globally.
  // The default behavior is 'explicit'.
  override strategy(): "explicit" | "all" {
    return "all";
  }

  // This function accepts query and parameters that cached into key param,
  // allowing you to retrieve response values for this query from the cache.
  override async get(key: string): Promise<any[] | undefined> {
    const res = (await this.kv.get(key)) ?? undefined;
    return res;
  }

  // This function accepts several options to define how cached data will be stored:
  // - 'key': A hashed query and parameters.
  // - 'response': An array of values returned by Drizzle from the database.
  // - 'tables': An array of tables involved in the select queries. This information is needed for cache invalidation.
  // - 'isTag': A boolean flag indicating whether this cache entry represents a tag-based query.
  //    When true, the entry is associated with a specific tag rather than table-level invalidation,
  //    allowing you to invalidate cached queries by tag name. See the UpstashCache:
  //    https://github.com/drizzle-team/drizzle-orm/blob/beta/drizzle-orm/src/cache/upstash/cache.ts for an example
  //
  // For example, if a query uses the "users" and "posts" tables, you can store this information. Later, when the app executes
  // any mutation statements on these tables, you can remove the corresponding key from the cache.
  // If you're okay with eventual consistency for your queries, you can skip this option.
  override async put(
    key: string,
    response: any,
    tables: string[],
    isTag: boolean = false,
    config?: CacheConfig,
  ): Promise<void> {
    const ttl = config?.px ?? (config?.ex ? config.ex * 1000 : this.globalTtl);

    await this.kv.set(key, response, ttl);

    for (const table of tables) {
      const keys = this.usedTablesPerKey[table];
      if (keys === undefined) {
        this.usedTablesPerKey[table] = [key];
      } else {
        keys.push(key);
      }
    }
  }

  // This function is called when insert, update, or delete statements are executed.
  // You can either skip this step or invalidate queries that used the affected tables.
  //
  // The function receives an object with two keys:
  // - 'tags': Used for queries labeled with a specific tag, allowing you to invalidate by that tag.
  // - 'tables': The actual tables affected by the insert, update, or delete statements,
  //   helping you track which tables have changed since the last cache update.
  override async onMutate(params: {
    tags: string | string[];
    tables: string | string[] | Table<any> | Table<any>[];
  }): Promise<void> {
    const tagsArray = params.tags
      ? Array.isArray(params.tags)
        ? params.tags
        : [params.tags]
      : [];
    const tablesArray = params.tables
      ? Array.isArray(params.tables)
        ? params.tables
        : [params.tables]
      : [];

    const keysToDelete = new Set<string>();

    for (const table of tablesArray) {
      const tableName = is(table, Table)
        ? getTableName(table)
        : (table as string);
      const keys = this.usedTablesPerKey[tableName] ?? [];
      for (const key of keys) keysToDelete.add(key);
    }

    if (keysToDelete.size > 0 || tagsArray.length > 0) {
      for (const tag of tagsArray) {
        await this.kv.delete(tag);
      }

      for (const key of keysToDelete) {
        await this.kv.delete(key);
        for (const table of tablesArray) {
          const tableName = is(table, Table)
            ? getTableName(table)
            : (table as string);
          this.usedTablesPerKey[tableName] = [];
        }
      }
    }
  }
}
```

## Limitations

#### Queries that won't be handled by the `cache` extension:

- Using cache with raw queries, such as:

```ts
db.execute(sql`select 1`);
```

```
- Using cache in transactions
```ts
await db.transaction(async (tx) => {
  await tx.update(accounts).set(...).where(...);
  await tx.update...
});
```

#### Limitations that are temporary and will be handled soon:

- Using cache with Drizzle Relational Queries
```ts
await db._query.users.findMany();
```

- Using cache with views


Source: https://orm.drizzle.team/docs/cockroach/column-types


import Section from '@mdx/Section.astro';
import Callout from '@mdx/Callout.astro';
import Npm from '@mdx/Npm.astro';

<Npm>
 drizzle-orm@rc
 drizzle-kit@rc -D
</Npm>

<br/>

We have native support for all of them, yet if that's not enough for you, feel free to create **[custom types](/docs/cockroach/custom-types)**.

<Callout title='important' type='warning'>
All examples in this part of the documentation do not use database column name aliases, and column names are generated from TypeScript keys. 

You can use database aliases in column names if you want, and you can also use the `casing` parameter to define a mapping strategy for Drizzle. 

You can read more about it [here](/docs/cockroach/sql-schema-declaration#shape-your-data-schema)
</Callout>

### bigint
`int` `int8` `int64` `integer`

Signed 8-byte integer     

If you're expecting values above 2^31 but below 2^53, you can utilize `mode: 'number'` and deal with javascript number as opposed to bigint.
<Section>
```typescript
import { int8, bigint, cockroachTable } from "drizzle-orm/cockroach-core";

export const table = cockroachTable('table', {
	int8: int8({ mode: 'number' })
	bigint: bigint({ mode: 'number' })
});

// will be inferred as `number`
int8: int8({ mode: 'number' })
bigint: bigint({ mode: 'number' })

// will be inferred as `bigint`
int8: int8({ mode: 'bigint' })
bigint: bigint({ mode: 'bigint' })
```

```sql
CREATE TABLE "table" (
	"int8" int8,
	"bigint" int8
);
```
</Section>

<Section>
```typescript
import { sql } from "drizzle-orm";
import { bigint, cockroachTable } from "drizzle-orm/cockroach-core";

export const table = cockroachTable('table', {
	bigint1: bigint().default(10),
	bigint2: int8().default(10),
});
```

```sql
CREATE TABLE "table" (
	"bigint1" bigint DEFAULT 10,
	"bigint2" int8 DEFAULT 10
);
```
</Section>

### smallint
`smallint` `int2`  
Small-range signed 2-byte integer   

<Section>
```typescript
import { smallint, cockroachTable } from "drizzle-orm/cockroach-core";

export const table = cockroachTable('table', {
	int2: int2(),
	smallint: smallint()
});
```

```sql
CREATE TABLE "table" (
	"int2" int2,
	"smallint" smallint
);
```
</Section>

<Section>
```typescript
import { sql } from "drizzle-orm";
import { int2, smallint, cockroachTable } from "drizzle-orm/cockroach-core";

export const table = cockroachTable('table', {
	smallint1: int2().default(10),
	smallint2: smallint().default(10)
});
```

```sql
CREATE TABLE "table" (
	"smallint1" int2 DEFAULT 10,
	"smallint2" int2 DEFAULT 10
);
```
</Section>

### int4

Signed 4-byte integer     

<Section>
```typescript
import { int4, cockroachTable } from "drizzle-orm/cockroach-core";

export const table = cockroachTable('table', {
	int4: int4()
});

```

```sql
CREATE TABLE "table" (
	"int4" int4
);
```
</Section>

<Section>
```typescript
import { sql } from "drizzle-orm";
import { int4, cockroachTable } from "drizzle-orm/cockroach-core";

export const table = cockroachTable('table', {
	int1: int4().default(10)
});
```

```sql
CREATE TABLE "table" (
	"int1" int4 DEFAULT 10
);
```
</Section>


### int8

An alias of **[bigint.](#bigint)**

### int2

An alias of **[smallint.](#smallint)**

### ---

### bool
Cockroach provides the standard SQL type bool.

For more info please refer to the official Cockroach **[docs.](https://www.cockroachlabs.com/docs/stable/bool)**

<Section>
```typescript
import { bool, cockroachTable } from "drizzle-orm/cockroach-core";

export const table = cockroachTable('table', {
	boolean: bool()
});

```

```sql
CREATE TABLE "table" (
	"boolean" bool
);
```
</Section>

## ---

### string
`text` `varchar`, `char`

The `STRING` data type stores a string of Unicode characters.

<Callout>
For PostgreSQL compatibility, CockroachDB supports the following STRING-related types and their aliases:

`VARCHAR` (and alias `CHARACTER VARYING`)
`CHAR` (and alias `CHARACTER`)
`NAME`
</Callout>

For more info please refer to the official CockroachDB **[docs.](https://www.cockroachlabs.com/docs/stable/string)**
  
You can define `{ enum: ["value1", "value2"] }` config to infer `insert` and `select` types, it **won't** check runtime values.
<Section>
```typescript
import { string, cockroachTable } from "drizzle-orm/cockroach-core";

export const table = cockroachTable('table', {
  stringColumn: string(), // equivalent to `text` PostgreSQL type
  stringColumn1: string({ length: 256 }), // equivalent to `varchar(256)` PostgreSQL type
});

// will be inferred as text: "value1" | "value2" | null
stringColumn: string({ enum: ["value1", "value2"] })
```

```sql
CREATE TABLE "table" (
	"stringColumn" string,
    "stringColumn1" string(256),
);
```
</Section>

### text

CockroachDB alias for `STRING`:

For more info please refer to the official CockroachDB **[docs.](https://www.cockroachlabs.com/docs/stable/string)**
  
You can define `{ enum: ["value1", "value2"] }` config to infer `insert` and `select` types, it **won't** check runtime values.
<Section>
```typescript
import { text, cockroachTable } from "drizzle-orm/cockroach-core";

export const table = cockroachTable('table', {
  text: text()
});

// will be inferred as text: "value1" | "value2" | null
text: text({ enum: ["value1", "value2"] })
```

```sql
CREATE TABLE "table" (
	"text" string
);
```
</Section>

### varchar
`character varying(n)` `varchar(n)`  

`STRING` alias used to stay compatible with PostgreSQL

For more info please refer to the official CockroachDB **[docs.](https://www.cockroachlabs.com/docs/stable/string)**

You can define `{ enum: ["value1", "value2"] }` config to infer `insert` and `select` types, it **won't** check runtime values.

The `length` parameter is optional for CockroachDB string types.
<Section>
```typescript
import { varchar, cockroachTable } from "drizzle-orm/cockroach-core";

export const table = cockroachTable('table', {
  varchar1: varchar(),
  varchar2: varchar({ length: 256 }),
});

// will be inferred as text: "value1" | "value2" | null
varchar: varchar({ enum: ["value1", "value2"] }),
```

```sql
CREATE TABLE "table" (
	"varchar1" varchar,
	"varchar2" varchar(256)
);
```
</Section>

### char
`character(n)` `char(n)`  

`STRING` alias used to stay compatible with PostgreSQL

For more info please refer to the official CockroachDB **[docs.](https://www.cockroachlabs.com/docs/stable/string)**

You can define `{ enum: ["value1", "value2"] }` config to infer `insert` and `select` types, it **won't** check runtime values.

The `length` parameter is optional for CockroachDB string types.
<Section>
```typescript
import { char, cockroachTable } from "drizzle-orm/cockroach-core";

export const table = cockroachTable('table', {
  char1: char(),
  char2: char({ length: 256 }),
});

// will be inferred as text: "value1" | "value2" | null
char: char({ enum: ["value1", "value2"] }),
```

```sql
CREATE TABLE "table" (
	"char1" char,
	"char2" char(256)
);
```
</Section>

## ---

https://www.cockroachlabs.com/docs/stable/float

### decimal

`numeric` `decimal` `dec`
The DECIMAL data type stores exact, fixed-point numbers. This type is used when it is important to preserve exact precision, for example, with monetary data.

For more info please refer to the official CockroachDB **[docs.](https://www.cockroachlabs.com/docs/stable/decimal)**

<Section>
```typescript
import { decimal, cockroachTable } from "drizzle-orm/cockroach-core";

export const table = cockroachTable('table', {
  decimal1: decimal(),
  decimal2: decimal({ precision: 100 }),
  decimal3: decimal({ precision: 100, scale: 20 }),
  decimalNum: decimal({ mode: 'number' }),
  decimalBig: decimal({ mode: 'bigint' }),
});
```

```sql
CREATE TABLE "table" (
	"decimal1" decimal,
	"decimal2" decimal(100),
	"decimal3" decimal(100, 20),
	"decimalNum" decimal,
	"decimalBig" decimal
);
```
</Section>

### numeric
An alias of **[decimal.](#decimal)**

### float
`float` `float8` `double precision`  

For more info please refer to the official CockroachDB **[docs.](https://www.cockroachlabs.com/docs/stable/float)**  

<Section>
```typescript
import { sql } from "drizzle-orm";
import { float, cockroachTable } from "drizzle-orm/cockroach-core";  

const table = cockroachTable('table', {
	float1: float(),
	float2: float().default(10.10),
	float3: float().default(sql`'10.10'::float`),
});
```

```sql
CREATE TABLE "table" (
	"float1" float,
	"float2" float default 10.10,
	"float3" float default '10.10'::float
);
```
</Section>

### real
`real` `float4`  
Single precision floating-point number (4 bytes)

For more info please refer to the official CockroachDB **[docs.](https://www.cockroachlabs.com/docs/stable/float)**  

<Section>
```typescript
import { sql } from "drizzle-orm";
import { real, cockroachTable } from "drizzle-orm/cockroach-core";  

const table = cockroachTable('table', {
	real1: real(),
	real2: real().default(10.10),
	real3: real().default(sql`'10.10'::real`),
});
```

```sql
CREATE TABLE "table" (
	"real1" real,
	"real2" real default 10.10,
	"real3" real default '10.10'::real
);
```
</Section>

### double precision

An alias of **[float.](#float)**

## ---

### jsonb
`jsonb`  

The JSONB data type stores JSON (JavaScript Object Notation) data as a binary representation of the JSONB value, which eliminates whitespace, duplicate keys, and key ordering

For more info please refer to the official CockroachDB **[docs.](https://www.cockroachlabs.com/docs/stable/jsonb)**
<Section>
```typescript
import { jsonb, cockroachTable } from "drizzle-orm/cockroach-core";

const table = cockroachTable('table', {
	jsonb1: jsonb(),
	jsonb2: jsonb().default({ foo: "bar" }),
	jsonb3: jsonb().default(sql`'{foo: "bar"}'::jsonb`),
});
```
```sql
CREATE TABLE "table" (
	"jsonb1" jsonb,
	"jsonb2" jsonb default '{"foo": "bar"}'::jsonb,
	"jsonb3" jsonb default '{"foo": "bar"}'::jsonb
);
```
</Section>

You can specify `.$type<..>()` for json object inference, it **won't** check runtime values. 
It provides compile time protection for default values, insert and select schemas.

```typescript
// will be inferred as { foo: string }
jsonb: jsonb().$type<{ foo: string }>();

// will be inferred as string[]
jsonb: jsonb().$type<string[]>();

// won't compile
jsonb: jsonb().$type<string[]>().default({});
```

## ---

### bit
`bit`  

The BIT data types store bit arrays. With BIT, the length is fixed.

<br />

**Size**

The number of bits in a BIT value is determined as follows:

| Type&nbsp;declaration		| Logical&nbsp;size	|
|:------------------		|:--------------	|
| BIT						| 1 bit				|
| BIT(N)					| N bits			|

<br />

For more info please refer to the official CockroachDB **[docs.](https://www.cockroachlabs.com/docs/stable/bit)**
<Section>
```typescript
import { sql } from "drizzle-orm";
import { cockroachTable, bit } from "drizzle-orm/cockroach-core";

export const table = cockroachTable('table', {
	bit1: bit(),
	bit2: bit({ length: 15 }),
	bit3: bit({ length: 15 }).default('10011'),
	bit4: bit({ length: 15 }).default(sql`'10011'`)
});
```
```sql
CREATE TABLE "table" (
	"bit1" bit,
	"bit2" bit(15),
	"bit3" bit(15) DEFAULT '10011',
	"bit4" bit(15) DEFAULT '10011'
);

```
</Section>

### varbit
`varbit`

The VARBIT data types store bit arrays. With VARBIT, the length can be variable.

<br />

**Size**

The number of bits in a VARBIT value is determined as follows:

| Type&nbsp;declaration		| Logical&nbsp;size													|
|:------------------		|:--------------													|
| VARBIT					| variable&nbsp;with&nbsp;no&nbsp;maximum							|
| VARBIT(N)					| variable&nbsp;with&nbsp;a&nbsp;maximum&nbsp;of&nbsp;N&nbsp;bits	|

<br />

For more info please refer to the official CockroachDB **[docs.](https://www.cockroachlabs.com/docs/stable/bit)**
<Section>
```typescript
import { sql } from "drizzle-orm";
import { cockroachTable, bit } from "drizzle-orm/cockroach-core";

export const table = cockroachTable('table', {
	varbit1: varbit(),
	varbit2: varbit({ length: 15 }),
	varbit3: varbit({ length: 15 }).default('10011'),
	varbit4: varbit({ length: 15 }).default(sql`'10011'`)
});
```
```sql
CREATE TABLE "table" (
	"varbit1" varbit,
	"varbit2" varbit(15),
	"varbit3" varbit(15) DEFAULT '10011',
	"varbit4" varbit(15) DEFAULT '10011'
);
```

</Section>

## ---

### uuid
`uuid`

The UUID (Universally Unique Identifier) data type stores a 128-bit value that is unique across both space and time.

For more info please refer to the official CockroachDB **[docs.](https://www.cockroachlabs.com/docs/stable/uuid)**

```ts
import { uuid, cockroachTable } from "drizzle-orm/cockroach-core";

const table = cockroachTable('table', {
  uuid1: uuid(),
  uuid2: uuid().defaultRandom(),
  uuid3: uuid().default('a0ee-bc99-9c0b-4ef8-bb6d-6bb9-bd38-0a11')
});
```

```sql
CREATE TABLE "table" (
	"uuid1" uuid,
	"uuid2" uuid default gen_random_uuid(),
	"uuid3" uuid default 'a0ee-bc99-9c0b-4ef8-bb6d-6bb9-bd38-0a11'
);
```

## ---

### time
`time` `timetz` `time with timezone` `time without timezone`  

The `TIME` data type stores the time of day in UTC.
The `TIMETZ` data type stores a time of day with a time zone offset from UTC.

For more info please refer to the official CockroachDB **[docs.](https://www.cockroachlabs.com/docs/stable/time)**

<Section>
```typescript
import { time, cockroachTable } from "drizzle-orm/cockroach-core";

const table = cockroachTable('table', {
  time1: time(),
  time2: time({ withTimezone: true }),
  time3: time({ precision: 6 }),
  time4: time({ precision: 6, withTimezone: true })
});
```

```sql
CREATE TABLE "table" (
	"time1" time,
	"time2" time with timezone,
	"time3" time(6),
	"time4" time(6) with timezone
);
```
</Section>

### timestamp
`timestamp` `timestamptz` `timestamp with time zone` `timestamp without time zone`  

The TIMESTAMP and TIMESTAMPTZ data types store a date and time pair in UTC.

For more info please refer to the official CockroachDB **[docs.](https://www.cockroachlabs.com/docs/stable/timestamp)**
<Section>
```typescript
import { sql } from "drizzle-orm";
import { timestamp, cockroachTable } from "drizzle-orm/cockroach-core";

const table = cockroachTable('table', {
  timestamp1: timestamp(),
	timestamp2: timestamp({ precision: 6, withTimezone: true }),
	timestamp3: timestamp().defaultNow(),
	timestamp4: timestamp().default(sql`now()`),
});
```
```sql
CREATE TABLE "table" (
	"timestamp1" timestamp,
	"timestamp2" timestamp (6) with time zone,
	"timestamp3" timestamp default now(),
	"timestamp4" timestamp default now()
);
```
</Section>

You can specify either `date` or `string` infer modes:
```typescript
// will infer as date
timestamp: timestamp({ mode: "date" }),

// will infer as string
timestamp: timestamp({ mode: "string" }),
```

> The `string` mode does not perform any mappings for you. This mode was added to Drizzle ORM to provide developers
with the possibility to handle dates and date mappings themselves, depending on their needs.
Drizzle will pass raw dates as strings `to` and `from` the database, so the behavior should be as predictable as possible 
and aligned 100% with the database behavior

> The `date` mode is the regular way to work with dates. Drizzle will take care of all mappings between the database and the JS Date object

### date
`date`  

The DATE data type stores a year, month, and day.

For more info please refer to the official CockroachDB **[docs.](https://www.cockroachlabs.com/docs/stable/date)**
<Section>
```typescript
import { date, cockroachTable } from "drizzle-orm/cockroach-core";

const table = cockroachTable('table', {
	date: date(),
});
```

```sql
CREATE TABLE "table" (
	"date" date
);
```
</Section>
You can specify either `date` or `string` infer modes:
```typescript
// will infer as date
date: date({ mode: "date" }),

// will infer as string
date: date({ mode: "string" }),
```
### interval
`interval`  

Stores a value that represents a span of time.

For more info please refer to the official CockroachDB **[docs.](https://www.cockroachlabs.com/docs/stable/interval)** 

<Section>
```typescript
import { interval, cockroachTable } from "drizzle-orm/cockroach-core";

const table = cockroachTable('table', {
	interval1: interval(),
  interval2: interval({ fields: 'day' }),
  interval3: interval({ fields: 'month' , precision: 6 }),
});

```

```sql
CREATE TABLE "table" (
	"interval1" interval,
	"interval2" interval day,
	"interval3" interval(6) month
);
```
</Section>

## ---

### enum 
`enum` `enumerated types`  
Enumerated (enum) types are data types that comprise a static, ordered set of values. 
They are equivalent to the enum types supported in a number of programming languages. 
An example of an enum type might be the days of the week, or a set of status values for a piece of data.

For more info please refer to the official CockroachDB **[docs.](https://www.cockroachlabs.com/docs/stable/enum)**
<Section>
```typescript
import { cockroachEnum, cockroachTable } from "drizzle-orm/cockroach-core";

export const moodEnum = cockroachEnum('mood', ['sad', 'ok', 'happy']);

export const table = cockroachTable('table', {
  mood: moodEnum(),
});
```

```sql
CREATE TYPE mood AS ENUM ('sad', 'ok', 'happy');

CREATE TABLE "table" (
	"mood" mood
);
```
</Section>

## ---

### geometry
`geometry`

The GEOMETRY data type stores 2D spatial data

For more info please refer to the official CockroachDB **[docs.](https://www.cockroachlabs.com/docs/stable/spatial-data-overview)**

<Section>
```typescript
import { geometry, cockroachTable } from "drizzle-orm/cockroach-core";

export const table = cockroachTable('table', {
  geo1: geometry({ type: 'point' }),
  geo2: geometry({ type: 'point', mode: 'xy' }),
  geo3: geometry({ type: 'point', srid: 4326 }),
});

// will be inferred as [number, number]
geo1: geometry({ type: 'point' })

// will be inferred as { x: number, y: number }
geo2: geometry({ type: 'point', mode: 'xy' })
```

```sql
CREATE TABLE "table" (
	"geo1" geometry(point),
	"geo2" geometry(point),
	"geo3" geometry(point,4326)
);
```
</Section>

### inet
`inet`

The INET data type stores an IPv4 or IPv6 address

For more info please refer to the official CockroachDB **[docs.](https://www.cockroachlabs.com/docs/stable/inet)**

<Section>
```typescript
import { inet, cockroachTable } from "drizzle-orm/cockroach-core";

export const table = cockroachTable('table', {
	inet: inet(),
});
```

```sql
CREATE TABLE "table" (
	"inet" inet
);
```
</Section>

### vector
`vector`

The `VECTOR` data type stores fixed-length arrays of floating-point numbers, which represent data points in multi-dimensional space

You must specify the number of `dimensions` for the vector.

<Section>
```typescript
import { vector, cockroachTable } from "drizzle-orm/cockroach-core";

export const table = cockroachTable('table', {
	embedding: vector({ dimensions: 3 }),
});
```

```sql
CREATE TABLE "table" (
	"embedding" vector(3)
);
```
</Section>

## ---

### Customizing data type
Every column builder has a `.$type()` method, which allows you to customize the data type of the column. 

This is useful, for example, with unknown or branded types:
```ts
type UserId = number & { __brand: 'user_id' };
type Data = {
	foo: string;
	bar: number;
};

const users = cockroachTable('users', {
  id: int4().$type<UserId>().primaryKey(),
  jsonbField: jsonb().$type<Data>(),
});
```

### Identity Columns

<Callout type="info">
To use this feature you would need to have `drizzle-orm@0.32.0` or higher and `drizzle-kit@0.23.0` or higher
</Callout>

PostgreSQL and CockroachDB supports identity columns as a way to automatically generate unique int4 values for a column. These values are generated using sequences and can be defined using the GENERATED AS IDENTITY clause.

**Types of Identity Columns**
- `GENERATED ALWAYS AS IDENTITY`: The database always generates a value for the column. Manual insertion or updates to this column are not allowed unless the OVERRIDING SYSTEM VALUE clause is used.
- `GENERATED BY DEFAULT AS IDENTITY`: The database generates a value by default, but manual values can also be inserted or updated. If a manual value is provided, it will be used instead of the system-generated value.

**Usage example**
```ts
import { cockroachTable, int4, text } from 'drizzle-orm/cockroach-core' 

export const ingredients = cockroachTable("ingredients", {
  id: int4().primaryKey().generatedAlwaysAsIdentity({ startWith: 1000 }),
  name: text().notNull(),
  description: text(),
});
```

You can specify all properties available for sequences in the `.generatedAlwaysAsIdentity()` function. Additionally, you can specify custom names for these sequences

CockroachDB docs [reference](https://www.cockroachlabs.com/docs/stable/create-table#parameters).

### Default value
The `DEFAULT` clause specifies a default value to use for the column if no value
is explicitly provided by the user when doing an `INSERT`.
If there is no explicit `DEFAULT` clause attached to a column definition,
then the default value of the column is `NULL`.

An explicit `DEFAULT` clause may specify that the default value is `NULL`,
a string constant, a blob constant, a signed-number, or any constant expression enclosed in parentheses.

<Section>
```typescript
import { sql } from "drizzle-orm";
import { int4, cockroachTable, uuid } from "drizzle-orm/cockroach-core";
import { sql } from 'drizzle-orm';

export const table = cockroachTable('table', {
	int: int4().default(42),
	uuid1: uuid().defaultRandom(),
	uuid2: uuid().default(sql`gen_random_uuid()`),
});
```

```sql
CREATE TABLE IF NOT EXISTS "table" (
	"int" int4 DEFAULT 42,
	"uuid1" uuid DEFAULT gen_random_uuid(),
	"uuid2" uuid DEFAULT gen_random_uuid()
);
```
</Section>

When using `$default()` or `$defaultFn()`, which are simply different aliases for the same function, 
you can generate defaults at runtime and use these values in all insert queries. 

These functions can assist you in utilizing various implementations such as `uuid`, `cuid`, `cuid2`, and many more.

<Callout type="info" emoji="ℹ️">
	Note: This value does not affect the `drizzle-kit` behavior, it is only used at runtime in `drizzle-orm`
</Callout>

```ts
import { text, cockroachTable } from "drizzle-orm/cockroach-core";
import { createId } from '@paralleldrive/cuid2';

export const table = cockroachTable('table', {
	id: text().$defaultFn(() => createId()),
});
```

When using `$onUpdate()` or `$onUpdateFn()`, which are simply different aliases for the same function, 
you can generate defaults at runtime and use these values in all update queries. 

Adds a dynamic update value to the column. The function will be called when the row is updated, 
and the returned value will be used as the column value if none is provided.
If no default (or $defaultFn) value is provided, the function will be called
when the row is inserted as well, and the returned value will be used as the column value.

<Callout type="info" emoji="ℹ️">
	Note: This value does not affect the `drizzle-kit` behavior, it is only used at runtime in `drizzle-orm`
</Callout>

```ts
import { int4, timestamp, text, cockroachTable } from "drizzle-orm/cockroach-core";

const table = cockroachTable('table', {
	updateCounter: int4().default(sql`1`).$onUpdateFn((): SQL => sql`${table.update_counter} + 1`),
	updatedAt: timestamp({ mode: 'date', precision: 3 }).$onUpdate(() => new Date()),
	alwaysNull: text().$type<string | null>().$onUpdate(() => null),
});
```


### Not null
`NOT NULL` constraint dictates that the associated column may not contain a `NULL` value.

<Section>
```typescript
import { int4, cockroachTable } from "drizzle-orm/cockroach-core";

const table = cockroachTable('table', {
	int4: int4().notNull(),
});
```

```sql
CREATE TABLE IF NOT EXISTS "table" (
	"int4" int4 NOT NULL
);
```
</Section>


### Primary key
A primary key constraint indicates that a column, or group of columns, can be used as a unique identifier for rows in the table. 
This requires that the values be both unique and not null.
<Section>
```typescript
import { int4, cockroachTable } from 'drizzle-orm/cockroach-core';

export const table = cockroachTable('table', {
  id: int4().primaryKey(),
});
```

```sql
CREATE TABLE IF NOT EXISTS "table" (
	"id" int4 PRIMARY KEY
);
```
</Section>


Source: https://orm.drizzle.team/docs/cockroach/connect-overview

# Database connection with Drizzle

Use these CockroachDB drivers and providers with Drizzle ORM.

## CockroachDB connection docs

- [CockroachDB](/docs/cockroach/get-started-cockroach)


Source: https://orm.drizzle.team/docs/cockroach/custom-types

import Callout from "@mdx/Callout.astro";

# Custom types

Custom types let you define your own column types with custom SQL data types and JS/DB value transforms

Cockroach exposes `customType` from `drizzle-orm/cockroach-core`.

## Examples
The best way to see how `customType` definition is working is to check how existing data types could be defined using `customType` function from Drizzle ORM.

#### Integer

```ts
import { customType, cockroachTable } from 'drizzle-orm/cockroach-core';

const customInteger = customType<{ data: number; }>(
  {
    dataType() {
      return 'int4';
    },
  },
);

export const users = cockroachTable("users", {
  id: customInteger(),
});
```

#### Text
```ts
import { customType, cockroachTable } from 'drizzle-orm/cockroach-core';

const customText = customType<{ data: string }>({
  dataType() {
    return 'text';
  },
});

export const users = cockroachTable('users', {
  name: customText(),
});
```

#### Timestamp
```ts
import { customType, cockroachTable } from 'drizzle-orm/cockroach-core';

const customTimestamp = customType<{
  data: Date;
  driverData: string;
  config: { withTimezone: boolean; precision?: number };
  configRequired: false;
}>({
  dataType(config) {
    const precision = typeof config?.precision !== 'undefined' ? ` (${config.precision})` : '';
    return `timestamp${config?.withTimezone ? 'tz' : ''}${precision}`;
  },
  fromDriver(value: string): Date {
    return new Date(value);
  },
});

export const users = cockroachTable('users', {
  createdAt: customTimestamp('created_at'),
});
```

Usage for all types will be same as defined functions in Drizzle ORM. For example:
```ts
const usersTable = cockroachTable('users', {
  id: customInteger().primaryKey(),
  name: customText().notNull(),
  createdAt: customTimestamp('created_at', { withTimezone: true }).notNull()
    .default(sql`now()`),
});
```

### TS-doc for type definitions
```ts
export type CustomTypeValues = {
	/**
	 * Required type for custom column, that will infer proper type model
	 *
	 * Examples:
	 *
	 * If you want your column to be `string` type after selecting/or on inserting - use `data: string`. Like `text`, `varchar`
	 *
	 * If you want your column to be `number` type after selecting/or on inserting - use `data: number`. Like `integer`
	 */
	data: unknown;

	/**
	 * Type helper, that represents what type database driver is accepting for specific database data type
	 */
	driverData?: unknown;

	/**
	 * Type helper, that represents what type database driver is returning for specific database data type
	 *
	 * Needed only in case driver's output and input for type differ
	 *
	 * Defaults to {@link driverData}
	 */
	driverOutput?: unknown;

	/**
	 * Type helper, that represents what type field returns after being aggregated to JSON
	 */
	jsonData?: unknown;

	/**
	 * What config type should be used for {@link CustomTypeParams} `dataType` generation
	 */
	config?: Record<string, any>;

	/**
	 * Whether the config argument should be required or not
	 * @default false
	 */
	configRequired?: boolean;

	/**
	 * If your custom data type should be notNull by default you can use `notNull: true`
	 *
	 * @example
	 * const customSerial = customType<{ data: number, notNull: true, default: true }>({
	 * 	  dataType() {
	 * 	    return 'serial';
	 *    },
	 * });
	 */
	notNull?: boolean;

	/**
	 * If your custom data type has default you can use `default: true`
	 *
	 * @example
	 * const customSerial = customType<{ data: number, notNull: true, default: true }>({
	 * 	  dataType() {
	 * 	    return 'serial';
	 *    },
	 * });
	 */
	default?: boolean;
};

export interface CustomTypeParams<T extends CustomTypeValues> {
	/**
	 * Database data type string representation, that is used for migrations
	 * @example
	 * ```
	 * `jsonb`, `text`
	 * ```
	 *
	 * If database data type needs additional params you can use them from `config` param
	 * @example
	 * ```
	 * `varchar(256)`, `numeric(2,3)`
	 * ```
	 *
	 * To make `config` be of specific type please use config generic in {@link CustomTypeValues}
	 *
	 * @example
	 * Usage example
	 * ```
	 *   dataType() {
	 *     return 'boolean';
	 *   },
	 * ```
	 * Or
	 * ```
	 *   dataType(config) {
	 * 	   return typeof config.length !== 'undefined' ? `varchar(${config.length})` : `varchar`;
	 * 	 }
	 * ```
	 */
	dataType: (config: T['config'] | (Equal<T['configRequired'], true> extends true ? never : undefined)) => string;

	/**
	 * Optional mapping function, that is used to transform inputs from desired to be used in code format to one suitable for driver
	 * @example
	 * For example, when using jsonb we need to map JS/TS object to string before writing to database
	 * ```
	 * toDriver(value: TData): string {
	 * 	 return JSON.stringify(value);
	 * }
	 * ```
	 */
	toDriver?: (value: T['data']) => T['driverData'] | SQL;

	/**
	 * Optional mapping function, that is used for transforming data returned by driver to desired column's output format
	 * @example
	 * For example, when using timestamp we need to map string Date representation to JS Date
	 * ```
	 * fromDriver(value: string): Date {
	 * 	return new Date(value);
	 * }
	 * ```
	 *
	 * It'll cause the returned data to change from:
	 * ```
	 * {
	 * 	customField: "2025-04-07T03:25:16.635Z";
	 * }
	 * ```
	 * to:
	 * ```
	 * {
	 * 	customField: new Date("2025-04-07T03:25:16.635Z");
	 * }
	 * ```
	 */
	fromDriver?: (value: 'driverOutput' extends keyof T ? T['driverOutput'] : T['driverData']) => T['data'];

	/**
	 * Optional mapping function, that is used for transforming data returned by transofmed to JSON in database data to desired format
	 *
	 * Used by [relational queries](https://orm.drizzle.team/docs/rqb)
	 *
	 * Defaults to {@link fromDriver} function
	 * @example
	 * For example, when querying bigint column via [RQB](https://orm.drizzle.team/docs/rqb) or [JSON functions](https://orm.drizzle.team/docs/json-functions), the result field will be returned as it's string representation, as opposed to bigint from regular query
	 * To handle that, we need a separate function to handle such field's mapping:
	 * ```
	 * fromJson(value: string): bigint {
	 * 	return BigInt(value);
	 * },
	 * ```
	 *
	 * It'll cause the returned data to change from:
	 * ```
	 * {
	 * 	customField: "5044565289845416380";
	 * }
	 * ```
	 * to:
	 * ```
	 * {
	 * 	customField: 5044565289845416380n;
	 * }
	 * ```
	 */
	fromJson?: (value: T['jsonData']) => T['data'];

	/**
	 * Optional selection modifier function, that is used for modifying selection of column inside [JSON functions](https://orm.drizzle.team/docs/json-functions)
	 *
	 * Additional mapping that could be required for such scenarios can be handled using {@link fromJson} function
	 *
	 * Used by [relational queries](https://orm.drizzle.team/docs/rqb)
	 *
	 * Following types are being casted to text by default: `bytea`, `geometry`, `timestamp`, `numeric`, `bigint`
	 * @example
	 * For example, when using bigint we need to cast field to text to preserve data integrity
	 * ```
	 * forJsonSelect(identifier: SQL, sql: SQLGenerator, arrayDimensions?: number): SQL {
	 * 	return sql`${identifier}::text`
	 * },
	 * ```
	 *
	 * This will change query from:
	 * ```
	 * SELECT
	 * 	row_to_json("t".*)
	 * 	FROM
	 * 	(
	 * 		SELECT
	 * 		"table"."custom_bigint" AS "bigint"
	 * 		FROM
	 * 		"table"
	 * 	) AS "t"
	 * ```
	 * to:
	 * ```
	 * SELECT
	 * 	row_to_json("t".*)
	 * 	FROM
	 * 	(
	 * 		SELECT
	 * 		"table"."custom_bigint"::text AS "bigint"
	 * 		FROM
	 * 		"table"
	 * 	) AS "t"
	 * ```
	 *
	 * Returned by query object will change from:
	 * ```
	 * {
	 * 	bigint: 5044565289845416000; // Partial data loss due to direct conversion to JSON format
	 * }
	 * ```
	 * to:
	 * ```
	 * {
	 * 	bigint: "5044565289845416380"; // Data is preserved due to conversion of field to text before JSON-ification
	 * }
	 * ```
	 */
	forJsonSelect?: (identifier: SQL, sql: SQLGenerator, arrayDimensions?: number) => SQL;
}
```

Source: https://orm.drizzle.team/docs/cockroach/data-querying

import Callout from '@mdx/Callout.astro';
import CodeTabs from "@mdx/CodeTabs.astro";
import Section from '@mdx/Section.astro';
import Flex from "@mdx/Flex.astro"
import LinksList from "@mdx/LinksList.astro"
import Prerequisites from "@mdx/Prerequisites.astro";

# Drizzle Queries + CRUD

<Prerequisites>
  - How to define your schema - [Schema Fundamentals](/docs/cockroach/sql-schema-declaration)
  - How to connect to the database - [Connection Fundamentals](/docs/cockroach/connect-overview)
</Prerequisites>

Drizzle gives you a few ways for querying your database and it's up to you to decide which one you'll need in your next project.
It can be either SQL-like syntax or Relational Syntax. Let's check them:

## Why SQL-like?
\
**If you know SQL, you know Drizzle.**

Other ORMs and data frameworks tend to deviate from or abstract away SQL, leading to a double learning curve: you need to learn both SQL and the framework's API.

Drizzle is the opposite.
We embrace SQL and built Drizzle to be SQL-like at its core, so you have little to no learning curve and full access to the power of SQL.

<Section>
```typescript copy
// Access your data
await db
  .select()
	.from(posts)
	.leftJoin(comments, eq(posts.id, comments.post_id))
	.where(eq(posts.id, 10))
```
```sql
SELECT *
FROM "posts"
LEFT JOIN "comments" ON "posts"."id" = "comments"."post_id"
WHERE "posts"."id" = 10
```
</Section>

With SQL-like syntax, you can replicate much of what you can do with pure SQL and know 
exactly what Drizzle will do and what query will be generated. You can perform a wide range of queries, 
including select, insert, update, delete, as well as using aliases, WITH clauses, subqueries, prepared statements, 
and more. Let's look at more examples

<CodeTabs items={['insert', 'update', 'delete']}>
<Section>
```ts
await db.insert(users).values({ email: 'user@gmail.com' })
```
```sql
INSERT INTO "users" ("email") VALUES ('user@gmail.com')
```
</Section>
<Section>
```ts
await db.update(users)
        .set({ email: 'user@gmail.com' })
        .where(eq(users.id, 1))
```
```sql
UPDATE "users"
SET "email" = 'user@gmail.com'
WHERE "users"."id" = 1
```
</Section>
<Section>
```ts
await db.delete(users).where(eq(users.id, 1))
```
```sql
DELETE FROM "users" WHERE "users"."id" = 1
```
</Section>
</CodeTabs>

## Why not SQL-like?

We're always striving for a perfectly balanced solution. While SQL-like queries cover 100% of your needs, 
there are certain common scenarios where data can be queried more efficiently.

We've built the Queries API so you can fetch relational, nested data from the database in the most convenient 
and performant way, without worrying about joins or data mapping.

**Drizzle always outputs exactly one SQL query**. Feel free to use it with serverless databases,
and never worry about performance or roundtrip costs!

<Section>
```ts
const result = await db._query.users.findMany({
	with: {
		posts: true
	},
});
```
{/* ```sql
SELECT * FROM users ...
``` */}
</Section>

## Advanced
With Drizzle, queries can be composed and partitioned in any way you want. You can compose filters 
independently from the main query, separate subqueries or conditional statements, and much more. 
Let's check a few advanced examples:

#### Compose a WHERE statement and then use it in a query
```ts
async function getProductsBy({
  name,
  category,
  maxPrice,
}: {
  name?: string;
  category?: string;
  maxPrice?: number;
}) {
  const filters: SQL[] = [];

  if (name) filters.push(ilike(products.name, name));
  if (category) filters.push(eq(products.category, category));
  if (maxPrice) filters.push(lte(products.price, maxPrice));

  return db
    .select()
    .from(products)
    .where(and(...filters));
}
```

#### Separate subqueries into different variables, and then use them in the main query
```ts
const subquery = db
	.select()
	.from(internalStaff)
	.leftJoin(customUser, eq(internalStaff.userId, customUser.id))
	.as('internal_staff');

const mainQuery = await db
	.select()
	.from(ticket)
	.leftJoin(subquery, eq(subquery.internal_staff.userId, ticket.staffId));
```

#### What's next?
<br/>
<Flex>
  <LinksList 
    title='Access your data'
    links={[
        ["Query", "/docs/cockroach/rqb"], 
        ["Select", "/docs/cockroach/select"],
        ["Insert", "/docs/cockroach/insert"],
        ["Update", "/docs/cockroach/update"],
        ["Delete", "/docs/cockroach/delete"],
        ["Filters", "/docs/cockroach/operators"],
        ["Joins", "/docs/cockroach/joins"],
        ["sql`` operator", "/docs/cockroach/sql"],
      ]}
  />
  <LinksList 
    title='Zero to Hero'
    links={[
        ["Migrations", "/docs/cockroach/migrations"], 
      ]}
  />
</Flex>


Source: https://orm.drizzle.team/docs/cockroach/delete

import Callout from '@mdx/Callout.astro';
import Section from '@mdx/Section.astro';

# SQL Delete

You can delete all rows in the table:
```typescript copy
await db.delete(users);
```
And you can delete with filters and conditions:
```typescript copy
await db.delete(users).where(eq(users.name, 'Dan'));
```

### Returning

You can delete a row and get it back in PostgreSQL:
```typescript copy
const deletedUser = await db.delete(users)
  .where(eq(users.name, 'Dan'))
  .returning();

// partial return
const deletedUserId = await db.delete(users)
  .where(eq(users.name, "Dan"))
  .returning({ deletedId: users.id });

// deletedUserId: { deletedId: number | null }[]
```
```sql
delete from "users" where "users"."name" = 'Dan' returning "id", "name";

delete from "users" where "users"."name" = 'Dan' returning "id";
```

## WITH DELETE clause

<Callout>
  Check how to use WITH statement with [select](/docs/cockroach/select#with-clause), [insert](/docs/cockroach/insert#with-insert-clause), [update](/docs/cockroach/update#with-update-clause)
</Callout>

Using the `with` clause can help you simplify complex queries by splitting them into smaller subqueries called common table expressions (CTEs):
<Section>
```typescript copy
const averageAmount = db.$with('average_amount').as(
  db.select({ value: sql`avg(${orders.amount})`.as('value') }).from(orders)
);

const result = await db
	.with(averageAmount)
	.delete(orders)
	.where(gt(orders.amount, sql`(select * from ${averageAmount})`))
	.returning({
		id: orders.id
	});
```
```sql
with "average_amount" as (select avg("amount") as "value" from "orders") 
delete from "orders" 
where "orders"."amount" > (select * from "average_amount") 
returning "id"
```
</Section>


Source: https://orm.drizzle.team/docs/cockroach/drizzle-config-file

import CodeTab from "@mdx/CodeTab.astro";
import CodeTabs from "@mdx/CodeTabs.astro";
import Section from "@mdx/Section.astro";
import Tab from "@mdx/Tab.astro";
import Tabs from "@mdx/Tabs.astro";
import Callout from "@mdx/Callout.astro";
import SchemaFilePaths from "@mdx/SchemaFilePaths.mdx"
import Prerequisites from "@mdx/Prerequisites.astro"
import Dialects from "@mdx/Dialects.mdx"
import Drivers from "@mdx/Drivers.mdx"
import DriversExamples from "@mdx/DriversExamples.mdx"
import Npx from "@mdx/Npx.astro"

# Drizzle Kit configuration file
<Prerequisites>
- Get started with Drizzle and `drizzle-kit` - [read here](/docs/cockroach/get-started)
- Drizzle schema fundamentals - [read here](/docs/cockroach/sql-schema-declaration)
- Database connection basics - [read here](/docs/cockroach/connect-overview)
- Drizzle migrations fundamentals - [read here](/docs/cockroach/migrations)
- Drizzle Kit [overview](/docs/cockroach/kit-overview) and [config file](/docs/cockroach/drizzle-config-file)
</Prerequisites>

Drizzle Kit lets you declare configuration options in `TypeScript` or `JavaScript` configuration files.

<Section>
```plaintext {5}
📦 <project root>
 ├ ...
 ├ 📂 drizzle
 ├ 📂 src
 ├ 📜 drizzle.config.ts
 └ 📜 package.json
```
<CodeTabs items={["drizzle.config.ts", "drizzle.config.js"]}>
<CodeTab>
```ts
import { defineConfig } from "drizzle-kit";

export default defineConfig({
  dialect: "cockroach",
  schema: "./src/schema.ts",
  out: "./drizzle",
});
```
</CodeTab>
<CodeTab>
```js
import { defineConfig } from "drizzle-kit";

export default defineConfig({
  dialect: "cockroach",
  schema: "./src/schema.ts",
  out: "./drizzle",
});
```
</CodeTab>
</CodeTabs>
</Section>

Example of an extended config file
```ts collapsable
import { defineConfig } from "drizzle-kit";

export default defineConfig({
  out: "./drizzle",
  dialect: "cockroach",
  schema: "./src/schema.ts",

  dbCredentials: {
    url: "./database/",
  },

  schemaFilter: "public",
  tablesFilter: "*",

  introspect: {
    casing: "camel",
  },

  migrations: {
    table: "__drizzle_migrations__",
    schema: "drizzle",
  },

  entities: {
    roles: {
      provider: '',
      exclude: [],
      include: []
    }
  },

  breakpoints: true,
  verbose: true,
});
```

### Multiple configuration files
You can have multiple config files in the project, it's very useful when you have multiple database stages or multiple databases or different databases on the same project:
<Npx>
  drizzle-kit generate --config=drizzle-dev.config.ts
  drizzle-kit generate --config=drizzle-prod.config.ts
</Npx>
```plaintext {5-6}
📦 <project root>
 ├ 📂 drizzle
 ├ 📂 src
 ├ 📜 .env
 ├ 📜 drizzle-dev.config.ts
 ├ 📜 drizzle-prod.config.ts
 ├ 📜 package.json
 └ 📜 tsconfig.json
```

### Migrations folder
`out` param lets you define folder for your migrations, it's optional and `drizzle` by default.  
It's very useful since you can have many separate schemas for different databases in the same project 
and have different migration folders for them.  
  
Migration folder contains folders with `.sql` migration files which is used by `drizzle-kit`

<Section>
```plaintext {3}
📦 <project root>
 ├ ...
 ├ 📂 drizzle
 │ ├ 📂 20242409125510_premium_mister_fear
 │ ├ 📜 user.ts 
 │ ├ 📜 post.ts 
 │ └ 📜 comment.ts 
 ├ 📂 src
 ├ 📜 drizzle.config.ts
 └ 📜 package.json
```
```ts {6}
import { defineConfig } from "drizzle-kit";

export default defineConfig({
  dialect: "cockroach",
  schema: "./src/schema/*",
  out: "./drizzle",
});
```
</Section>

## ---

### `dialect`
<rem025/>

Dialect of the database you're using 
|               |                                                 |
| :------------ | :-----------------------------------            |
| type        | <Dialects/>                                     |
| default        | --                                     |
| commands    | `generate`, `push`, `pull`, `studio`,  `migrate`, `up`, `export` |

<rem025/>
```ts {4}
import { defineConfig } from "drizzle-kit";

export default defineConfig({
  dialect: "cockroach", 
});
```


### `schema`
<rem025/>

[`glob`](https://www.digitalocean.com/community/tools/glob?comments=true&glob=/**/*.js&matches=false&tests=//%20This%20will%20match%20as%20it%20ends%20with%20'.js'&tests=/hello/world.js&tests=//%20This%20won't%20match!&tests=/test/some/globs)
 based path to drizzle schema file(s) or folder(s) contaning schema files.
|               |                      |
| :------------ | :-----------------   |
| type          | `string` `string[]` |
| default        | --                    |
| commands      | `generate`, `push`, `export`, `studio`  |

<rem025/>
<SchemaFilePaths />


### `out`
<rem025/>

Defines output folder of your SQL migration files, json snapshots of your schema and `schema.ts` from `drizzle-kit pull` command.
|               |                      |
| :------------ | :-----------------   |
| type          | `string` `string[]` |
| default        | `drizzle`                    |
| commands      | `generate`, `pull`, `migrate`, `check`, `up` |

<rem025/>
```ts {4}
import { defineConfig } from "drizzle-kit";

export default defineConfig({
  out: "./drizzle", 
});
```

## ---

### `dbCredentials`
<rem025/>

Database connection credentials in a form of `url`, 
`user:password@host:port/db` params or exceptions drivers(<Drivers/>) specific connection options.

|               |                      |
| :------------ | :-----------------   |
| type          | <Dialects/> |
| default       | --                    |
| commands      | `push`, `pull`, `migrate`, `studio` |

<rem025/>

<CodeTabs items={["Connection string", "Connection params"]}>
```ts
import { defineConfig } from 'drizzle-kit'

export default defineConfig({
  dialect: "cockroach",
  dbCredentials: {
    url: "postgres://user:password@host:port/db",
  }
});
```
```ts
import { defineConfig } from 'drizzle-kit'

export default defineConfig({
  dialect: "cockroach",
  dbCredentials: {
    host: "host",
    port: 26257,
    user: "user",
    password: "password",
    database: "dbname",
    ssl: true, // can be boolean | "require" | "allow" | "prefer" | "verify-full" | options from node:tls
  }
});
```
</CodeTabs>

### `migrations`
<rem025/>

When running `drizzle-kit migrate` - drizzle will records about 
successfully applied migrations in your database in log table named `__drizzle_migrations` in `drizzle` schema.

`migrations` config options lets you change both migrations log `table` name and `schema`.

|               |                      |
| :------------ | :-----------------   |
| type          | `{ table: string, schema: string }` |
| default       | `{ table: "__drizzle_migrations", schema: "drizzle" }`                    |
| commands      | `migrate`, `push`, `pull` |

<rem025/>

```ts
export default defineConfig({
  dialect: "cockroach",
  schema: "./src/schema.ts",
  migrations: {
    table: 'my-migrations-table', // `__drizzle_migrations` by default
    schema: 'my_schema', // `drizzle` by default
  },
});
```

### `introspect`
<rem025/>

Configuration for `drizzle-kit pull` command.

`casing` is responsible for in-code column keys casing

|               |                      |
| :------------ | :-----------------   |
| type          | `{ casing: "preserve" \| "camel" }` |
| default       | `{ casing: "camel" }`                    |
| commands      | `pull`   |

<rem025/>

<CodeTabs items={["camel", "preserve"]}>
<Section>
```ts
import * as p from "drizzle-orm/cockroach-core"

export const users = p.cockroachTable("users", {
  id: p.int4(),
  firstName: p.string("first-name"),
  lastName: p.string("LastName"),
  email: p.string(),
  phoneNumber: p.string("phone_number"),
});
```
```sql
SELECT column_name as column_name, lower(crdb_sql_type) as data_type FROM information_schema.columns WHERE table_name = 'users';
```
``` 
 column_name   | data_type        
---------------+------------------------
 id            | int4
 first-name    | string
 LastName      | string
 email         | string
 phone_number  | string
```
</Section>
<Section>
```ts
import * as p from "drizzle-orm/cockroach-core"

export const users = p.cockroachTable("users", {
  id: p.int4(),
  "first-name": p.string("first-name"),
  LastName: p.string("LastName"),
  email: p.string(),
  phone_number: p.string("phone_number"),
});
```
```sql
SELECT column_name as column_name, lower(crdb_sql_type) as data_type FROM information_schema.columns WHERE table_name = 'users';
```
``` 
 column_name   | data_type        
---------------+------------------------
 id            | int4
 first-name    | string
 LastName      | string
 email         | string
 phone_number  | string
```
</Section>
</CodeTabs>


## --- 

### `tablesFilter`
<Callout>
If you want to run multiple projects with one database - check out [our guide](/docs/cockroach/goodies#multi-project-schema).
</Callout>
<rem025/>
`drizzle-kit push` and `drizzle-kit pull` will manage all tables by default.
You can configure list of tables, schemas and extensions via `tablesFilters`, `schemaFilter` and `extensionFilters` options.

`tablesFilter` option lets you specify [`glob`](https://www.digitalocean.com/community/tools/glob?comments=true&glob=/**/*.js&matches=false&tests=//%20This%20will%20match%20as%20it%20ends%20with%20'.js'&tests=/hello/world.js&tests=//%20This%20won't%20match!&tests=/test/some/globs) 
based table names filter, e.g. `["users", "user_info"]` or `"user*"`

|               |                      |
| :------------ | :-----------------   |
| type          | `string` `string[]` |
| default       | --                    |
| commands      | `push` `pull`   |

<rem025/>
```ts
import { defineConfig } from "drizzle-kit";

export default defineConfig({
  dialect: "cockroach",
  tablesFilter: ["users", "posts", "project1_*"],
});
```

### `schemaFilter`


<Callout>
If you want to run multiple projects with one database - check out [our guide](/docs/cockroach/goodies#multi-project-schema).
</Callout>

`drizzle-kit push` and `drizzle-kit pull` will by default manage all schemas.

`schemaFilter` option lets you specify [`glob`](https://www.digitalocean.com/community/tools/glob?comments=true&glob=/**/*.js&matches=false&tests=//%20This%20will%20match%20as%20it%20ends%20with%20'.js'&tests=/hello/world.js&tests=//%20This%20won't%20match!&tests=/test/some/globs) 
based schema names filter, e.g. `["public", "auth"]` or `"tenant_*"`

|               |                      |
| :------------ | :-----------------   |
| type          | `string[]` |
| commands      | `push` `pull`   |

<rem025/>

```ts
export default defineConfig({
  dialect: "cockroach",
  schemaFilter: ["public", "schema1", "schema2"],
});
```

## ---

### `entities`

This configuration is created to set up management settings for specific `entities` in the database. 

For now, it only includes `roles`, but eventually all database entities will migrate here, such as `tables`, `schemas`, `extensions`, `functions`, `triggers`, etc

#### `roles`

<rem025/>

If you are using Drizzle Kit to manage your schema and especially the defined roles, there may be situations where you have some roles that are not defined in the Drizzle schema. 
In such cases, you may want Drizzle Kit to skip those `roles` without the need to write each role in your Drizzle schema and mark it with `.existing()`.

The `roles` option lets you:

- Enable or disable role management with Drizzle Kit.
- Exclude specific roles from management by Drizzle Kit.
- Include specific roles for management by Drizzle Kit.
- Enable modes for providers like `Neon` and `Supabase`, which do not manage their specific roles.
- Combine all the options above

|               |                       |
| :------------ | :-----------------    |
| type          | `boolean \| { provider: "neon" \| "supabase", include: string[], exclude: string[] }`|
| default       | `false`                  |
| commands      | `push` `pull` |

<rem025/>

By default, `drizzle-kit` won't manage roles for you, so you will need to enable that. in `drizzle.config.ts`
```ts
export default defineConfig({
  dialect: "cockroach",
  entities: {
    roles: true
  }
});
```

**You have a role `admin` and want to exclude it from the list of manageable roles**

```ts
// drizzle.config.ts
import { defineConfig } from "drizzle-kit";

export default defineConfig({
  ...
  entities: {
    roles: {
      exclude: ['admin']
    }
  }
});
```

**You have a role `admin` and want to include to the list of manageable roles**

```ts
// drizzle.config.ts
import { defineConfig } from "drizzle-kit";

export default defineConfig({
  ...
  entities: {
    roles: {
      include: ['admin']
    }
  }
});
```

**If you are using `Neon` and want to exclude roles defined by `Neon`, you can use the provider option**

```ts
// drizzle.config.ts
import { defineConfig } from "drizzle-kit";

export default defineConfig({
  ...
  entities: {
    roles: {
      provider: 'neon'
    }
  }
});
```

**If you are using `Supabase` and want to exclude roles defined by `Supabase`, you can use the provider option**

```ts
// drizzle.config.ts
import { defineConfig } from "drizzle-kit";

export default defineConfig({
  ...
  entities: {
    roles: {
      provider: 'supabase'
    }
  }
});
```

<Callout title='important'>
You may encounter situations where Drizzle is slightly outdated compared to new roles specified by database providers, 
so you may need to use both the `provider` option and `exclude` additional roles. You can easily do this with Drizzle:

```ts
// drizzle.config.ts
import { defineConfig } from "drizzle-kit";

export default defineConfig({
  ...
  entities: {
    roles: {
      provider: 'supabase',
      exclude: ['new_supabase_role']
    }
  }
});
```
</Callout>

## ---

### `verbose`
<rem025/>

Print all SQL statements during `drizzle-kit push` command.

|               |                      |
| :------------ | :-----------------   |
| type          | `boolean` |
| default       | `false`                    |
| commands      | `pull`   |

<rem025/>

```ts
export default defineConfig({
  dialect: "cockroach",
  verbose: false,
});
```

### `breakpoints`
<rem025/>

Drizzle Kit will automatically embed `--> statement-breakpoint` into generated SQL migration files, 
that's necessary for databases that do not support multiple DDL alternation statements in one transaction(MySQL and SQLite).

`breakpoints` option flag lets you switch it on and off

|               |                      |
| :------------ | :-----------------   |
| type          | `boolean` |
| default       | `true`                    |
| commands      | `generate` `pull`   |

<rem025/>

```ts
export default defineConfig({
  dialect: "cockroach",
  breakpoints: false,
});
```


Source: https://orm.drizzle.team/docs/cockroach/drizzle-kit-check

import CodeTab from "@mdx/CodeTab.astro";
import CodeTabs from "@mdx/CodeTabs.astro";
import Section from "@mdx/Section.astro";
import Tab from "@mdx/Tab.astro";
import Tabs from "@mdx/Tabs.astro";
import Callout from "@mdx/Callout.astro";
import Prerequisites from "@mdx/Prerequisites.astro";
import Npm from "@mdx/Npm.astro";
import Npx from "@mdx/Npx.astro";
import Dialects from "@mdx/Dialects.mdx"

# `drizzle-kit check`

<Prerequisites>
- Get started with Drizzle and `drizzle-kit` - [read here](/docs/cockroach/get-started)
- Drizzle schema fundamentals - [read here](/docs/cockroach/sql-schema-declaration)
- Database connection basics - [read here](/docs/cockroach/connect-overview)
- Drizzle migrations fundamentals - [read here](/docs/cockroach/migrations)
- Drizzle Kit [overview](/docs/cockroach/kit-overview) and [config file](/docs/cockroach/drizzle-config-file)
- `drizzle-kit generate` command - [read here](/docs/cockroach/drizzle-kit-generate)
</Prerequisites>

`drizzle-kit check` command lets you check consistency of your generated SQL migrations history.

That's extremely useful when you have multiple developers working on the project and 
altering database schema on different branches - read more about [migrations for teams](/docs/cockroach/kit-migrations-for-teams).

<br/>
<hr/>
<br/>

`drizzle-kit check` command requires you to specify `dialect`, 
you can provide it either via [drizzle.config.ts](/docs/cockroach/drizzle-config-file) config file or via CLI options

<CodeTabs items={["With config file", "As CLI options"]}>
<Section>
```ts {5,8}
// drizzle.config.ts
import { defineConfig } from "drizzle-kit";

export default defineConfig({
  dialect: "cockroach",
});
```
```shell
npx drizzle-kit check
```
</Section>
```shell
npx drizzle-kit check --dialect=cockroach
```
</CodeTabs>

### Multiple configuration files in one project
You can have multiple config files in the project, it's very useful when you have multiple database stages or multiple databases on the same project:
<Npx>
  drizzle-kit check --config=drizzle-dev.config.ts
  drizzle-kit check --config=drizzle-prod.config.ts
</Npx>
```plaintext {5-6}
📦 <project root>
 ├ 📂 drizzle
 ├ 📂 src
 ├ 📜 .env
 ├ 📜 drizzle-dev.config.ts
 ├ 📜 drizzle-prod.config.ts
 ├ 📜 package.json
 └ 📜 tsconfig.json
```

### Ignore conflicts

In case you need `check` command to skip commutativity checks and bypass it, you can use `--ignore-conflicts`. If there is a situation you want to use it, then
there is a big chance that `drizzle-kit` didn't check migrations right and it's a bug. Please report us your case, so we can fix it

```shell
drizzle-kit check --ignore-conflicts
```

### Extended list of configurations
We recommend configuring `drizzle-kit` through [drizzle.config.ts](/docs/cockroach/drizzle-config-file) file, 
yet you can provide all configuration options through CLI if necessary, e.g. in CI/CD pipelines, etc.
<rem025/>
|           |            |                                                                         |
| :-------- | :--------- | :---------------------------------------------------------------------- |
| `dialect` | `required` | Database dialect you are using. Can be one of <Dialects/> |
| `out`     |            | Migrations folder, default=`./drizzle`                                         |
| `config`  |            | Configuration file path, default=`drizzle.config.ts`                           |
<br/>
<Npx>
drizzle-kit check --dialect=cockroach
drizzle-kit check --dialect=cockroach --out=./migrations-folder
</Npx>


Source: https://orm.drizzle.team/docs/cockroach/drizzle-kit-export

import CodeTab from "@mdx/CodeTab.astro";
import CodeTabs from "@mdx/CodeTabs.astro";
import Section from "@mdx/Section.astro";
import Tab from "@mdx/Tab.astro";
import Tabs from "@mdx/Tabs.astro";
import Callout from "@mdx/Callout.astro";
import Prerequisites from "@mdx/Prerequisites.astro"
import Npx from "@mdx/Npx.astro";
import SchemaFilePaths from "@mdx/SchemaFilePaths.mdx"
import Dialects from "@mdx/Dialects.mdx"

# `drizzle-kit export` 

<Prerequisites>
- Get started with Drizzle and `drizzle-kit` - [read here](/docs/cockroach/get-started)
- Drizzle schema fundamentals - [read here](/docs/cockroach/sql-schema-declaration)
- Database connection basics - [read here](/docs/cockroach/connect-overview)
- Drizzle migrations fundamentals - [read here](/docs/cockroach/migrations)
- Drizzle Kit [overview](/docs/cockroach/kit-overview) and [config file](/docs/cockroach/drizzle-config-file)
</Prerequisites>


<br/>

`drizzle-kit export` lets you export SQL representation of Drizzle schema and print in console SQL DDL representation on it.
<Callout collapsed="How it works under the hood?">
Drizzle Kit `export` command triggers a sequence of events:
1. It will read through your Drizzle schema file(s) and compose a json snapshot of your schema
2. Based on the current json snapshot it will generate SQL DDL statements
3. Output SQL DDL statements to console
</Callout>

It's designed to cover [codebase first](/docs/cockroach/migrations) approach of managing Drizzle migrations. 
You can export the SQL representation of the Drizzle schema, allowing external tools like Atlas to handle all the migrations for you

`drizzle-kit export` command requires you to provide both `dialect` and `schema` path options, 
you can set them either via [drizzle.config.ts](/docs/cockroach/drizzle-config-file) config file or via CLI options
<CodeTabs items={["With config file", "As CLI options"]}>
<Section>
```ts
// drizzle.config.ts
import { defineConfig } from "drizzle-kit";

export default defineConfig({
  dialect: "cockroach",
  schema: "./src/schema.ts",
});
```
```shell
npx drizzle-kit export
```
</Section>

```shell
npx drizzle-kit export --dialect=cockroach --schema=./src/schema.ts
```
</CodeTabs>

### Schema files path
You can have a single `schema.ts` file or as many schema files as you want spread out across the project. 
Drizzle Kit requires you to specify path(s) to them as a [glob](https://www.digitalocean.com/community/tools/glob?comments=true&glob=/**/*.js&matches=false&tests=//%20This%20will%20match%20as%20it%20ends%20with%20'.js'&tests=/hello/world.js&tests=//%20This%20won't%20match!&tests=/test/some/globs) via `schema` configuration option.

<SchemaFilePaths/>

### Multiple configuration files in one project
You can have multiple config files in the project, it's very useful when you have multiple database stages or multiple databases or different databases on the same project:
<Npx>
  drizzle-kit export --config=drizzle-dev.config.ts
  drizzle-kit export --config=drizzle-prod.config.ts
</Npx>
```plaintext {5-6}
📦 <project root>
 ├ 📂 drizzle
 ├ 📂 src
 ├ 📜 .env
 ├ 📜 drizzle-dev.config.ts
 ├ 📜 drizzle-prod.config.ts
 ├ 📜 package.json
 └ 📜 tsconfig.json
```

### Extended list of available configurations
`drizzle-kit export` has a list of cli-only options

<rem025/>

|               |                                                      |
| :--------     | :--------------------------------------------------- |
| `--sql`       | generating SQL representation of Drizzle Schema               |

By default, Drizzle Kit outputs SQL files, but in the future, we want to support different formats

<rem025/>

<Npx>
drizzle-kit export --sql=true
</Npx>

<br/>
<hr/>
<br/>
We recommend configuring `drizzle-kit` through [drizzle.config.ts](/docs/cockroach/drizzle-config-file) file, 
yet you can provide all configuration options through CLI if necessary, e.g. in CI/CD pipelines, etc.

|               |            |                                                                            |
| :------------ | :-------   | :----------------------------------------------------------------------    |
| `dialect`     | `required` | Database dialect, one of <Dialects/>                                       |
| `schema`      | `required` | Path to typescript schema file(s) or folder(s) with multiple schema files  |
| `config`      |            | Configuration file path, default is `drizzle.config.ts`                    |

### Example
Example of how to export drizzle schema to console with Drizzle schema located in `./src/schema.ts`

We will also place drizzle config file in the `configs` folder.

Let's create config file:

```plaintext {4}
📦 <project root>
 ├ 📂 configs
 │ └ 📜 drizzle.config.ts
 ├ 📂 src
 │ └ 📜 schema.ts
 └ …
```
```ts filename='drizzle.config.ts'
import { defineConfig } from "drizzle-kit";

export default defineConfig({
  dialect: "cockroach",
  schema: "./src/schema.ts",
});
```

```ts filename='schema.ts'
import { cockroachTable, int4, string } from 'drizzle-orm/cockroach-core'

export const users = cockroachTable('users', {
	id: int4('id').primaryKey(),
	email: string('email').notNull(),
	name: string('name')
});
```

Now let's run
```shell
npx drizzle-kit export --config=./configs/drizzle.config.ts
```
And it will successfully output SQL representation of drizzle schema
```bash
CREATE TABLE "users" (
        "id" int4 PRIMARY KEY,
        "email" string NOT NULL,
        "name" string
);
```

Source: https://orm.drizzle.team/docs/cockroach/drizzle-kit-generate

import CodeTab from "@mdx/CodeTab.astro";
import CodeTabs from "@mdx/CodeTabs.astro";
import Section from "@mdx/Section.astro";
import Tab from "@mdx/Tab.astro";
import Tabs from "@mdx/Tabs.astro";
import Callout from "@mdx/Callout.astro";
import Prerequisites from "@mdx/Prerequisites.astro"
import Npx from "@mdx/Npx.astro";
import SchemaFilePaths from "@mdx/SchemaFilePaths.mdx"
import Dialects from "@mdx/Dialects.mdx"

# `drizzle-kit generate` 

<Prerequisites>
- Get started with Drizzle and `drizzle-kit` - [read here](/docs/cockroach/get-started)
- Drizzle schema fundamentals - [read here](/docs/cockroach/sql-schema-declaration)
- Database connection basics - [read here](/docs/cockroach/connect-overview)
- Drizzle migrations fundamentals - [read here](/docs/cockroach/migrations)
- Drizzle Kit [overview](/docs/cockroach/kit-overview) and [config file](/docs/cockroach/drizzle-config-file)
</Prerequisites>


<br/>

`drizzle-kit generate` lets you generate SQL migrations based on your Drizzle schema upon declaration or on subsequent schema changes.
<Callout collapsed="How it works under the hood?">
Drizzle Kit `generate` command triggers a sequence of events:
1. It will read through your Drizzle schema file(s) and compose a json snapshot of your schema
2. It will read through your previous migrations folders and compare current json snapshot to the most recent one
3. Based on json differences it will generate SQL migrations
4. Save `migration.sql` and `snapshot.json` in migration folder under current timestamp

<Section>
```typescript filename="src/schema.ts"
import * as p from "drizzle-orm/cockroach-core";

export const users = p.cockroachTable("users", {
  id: p.int4().primaryKey(),
  name: p.string(),
  email: p.string().unique(), 
});
```
```                                  
┌────────────────────────┐                  
│ $ drizzle-kit generate │                  
└─┬──────────────────────┘                  
  │                                           
  └ 1. read previous migration folders
    2. find diff between current and previous schema
    3. prompt developer for renames if necessary
  ┌ 4. generate SQL migration and persist to file
  │    ┌─┴───────────────────────────────────────┐  
  │      📂 drizzle       
  │      └ 📂 20242409125510_premium_mister_fear
  │        ├ 📜 migration.sql
  │        └ 📜 snapshot.json
  v
```
```sql
-- drizzle/20242409125510_premium_mister_fear/migration.sql

CREATE TABLE "users" (
	"id" int4 PRIMARY KEY,
	"name" string,
	"email" string,
	CONSTRAINT "users_email_key" UNIQUE("email")
);
```
</Section>
</Callout>

It's designed to cover [code first](/docs/cockroach/migrations) approach of managing Drizzle migrations. 
You can apply generated migrations using [`drizzle-kit migrate`](/docs/cockroach/drizzle-kit-migrate), using drizzle-orm's `migrate()`, 
using external migration tools like [bytebase](https://www.bytebase.com/) or running migrations yourself directly on the database. 

`drizzle-kit generate` command requires you to provide both `dialect` and `schema` path options, 
you can set them either via [drizzle.config.ts](/docs/cockroach/drizzle-config-file) config file or via CLI options
<CodeTabs items={["With config file", "As CLI options"]}>
<Section>
```ts
// drizzle.config.ts
import { defineConfig } from "drizzle-kit";

export default defineConfig({
  dialect: "cockroach",
  schema: "./src/schema.ts",
});
```
```shell
npx drizzle-kit generate
```
</Section>

```shell
npx drizzle-kit generate --dialect=cockroach --schema=./src/schema.ts
```
</CodeTabs>

### Schema files path
You can have a single `schema.ts` file or as many schema files as you want spread out across the project. 
Drizzle Kit requires you to specify path(s) to them as a [glob](https://www.digitalocean.com/community/tools/glob?comments=true&glob=/**/*.js&matches=false&tests=//%20This%20will%20match%20as%20it%20ends%20with%20'.js'&tests=/hello/world.js&tests=//%20This%20won't%20match!&tests=/test/some/globs) via `schema` configuration option.

<SchemaFilePaths/>


### Custom migration file name
You can set custom migration file names by providing `--name` CLI option
```shell
npx drizzle-kit generate --name=init
```
```plaintext {4}
📦 <project root>
 ├ 📂 drizzle
 │ └ 📂 20242409125510_init
 │   ├ 📜 snapshot.json
 │   └ 📜 migration.sql
 ├ 📂 src
 └ …
```

### Multiple configuration files in one project
You can have multiple config files in the project, it's very useful when you have multiple database stages or multiple databases or different databases on the same project:
<Npx>
  drizzle-kit generate --config=drizzle-dev.config.ts
  drizzle-kit generate --config=drizzle-prod.config.ts
</Npx>
```plaintext {5-6}
📦 <project root>
 ├ 📂 drizzle
 ├ 📂 src
 ├ 📜 .env
 ├ 📜 drizzle-dev.config.ts
 ├ 📜 drizzle-prod.config.ts
 ├ 📜 package.json
 └ 📜 tsconfig.json
```

### Custom migrations
You can generate empty migration files to write your own custom SQL migrations 
for DDL alternations currently not supported by Drizzle Kit or data seeding. Extended docs on custom migrations - [see here](/docs/cockroach/kit-custom-migrations)

```shell
drizzle-kit generate --custom --name=seed-users
```
<Section>
```plaintext {5}
📦 <project root>
 ├ 📂 drizzle
 │ ├ 📂 20242409125510_init
 │ └ 📂 20242409125510_seed-users
 ├ 📂 src
 └ …
```
```sql
-- ./drizzle/20242409125510_seed/migration.sql

INSERT INTO "users" ("name") VALUES('Dan');
INSERT INTO "users" ("name") VALUES('Andrew');
INSERT INTO "users" ("name") VALUES('Dandrew');
```
</Section>

### Ignore conflicts

In case you need `generate` command to skip commutativity checks and bypass it, you can use `--ignore-conflicts`. If there is a situation you want to use it, then
there is a big chance that `drizzle-kit` didn't check migrations right and it's a bug. Please report us your case, so we can fix it

```shell
drizzle-kit generate --ignore-conflicts
```

### Extended list of available configurations
`drizzle-kit generate` has a list of cli-only options

<rem025/>

|               |                                                      |
| :--------     | :--------------------------------------------------- |
| `custom`      | generate empty SQL for custom migration              |
| `name`        | generate migration with custom name                  |
| `ignore-conflicts` | skip commutativity conflict checks, default is `false` |
<rem025/>

<Npx>
drizzle-kit generate --name=init
drizzle-kit generate --name=seed_users --custom
drizzle-kit generate --ignore-conflicts
</Npx>

<br/>
<hr/>
<br/>
We recommend configuring `drizzle-kit` through [drizzle.config.ts](/docs/cockroach/drizzle-config-file) file, 
yet you can provide all configuration options through CLI if necessary, e.g. in CI/CD pipelines, etc.

|               |            |                                                                            |
| :------------ | :-------   | :----------------------------------------------------------------------    |
| `dialect`     | `required` | Database dialect, one of <Dialects/>                                       |
| `schema`      | `required` | Path to typescript schema file(s) or folder(s) with multiple schema files  |
| `out`         |            | Migrations output folder, default is `./drizzle`                           |
| `config`      |            | Configuration file path, default is `drizzle.config.ts`                    |
| `breakpoints` |            | SQL statements breakpoints, default is `true`                              |


### Extended example
Example of how to create a custom cockroach migration file named `0001_seed-users.sql` 
with Drizzle schema located in `./src/schema.ts` and migrations folder named `./migrations` instead of default `./drizzle`.

We will also place drizzle config file in the `configs` folder.

Let's create config file:

```plaintext {4}
📦 <project root>
 ├ 📂 migrations
 ├ 📂 configs
 │ └ 📜 drizzle.config.ts
 ├ 📂 src
 └ …
```
```ts filename='drizzle.config.ts'
import { defineConfig } from "drizzle-kit";

export default defineConfig({
  dialect: "cockroach",
  schema: "./src/schema.ts",
  out: "./migrations",
});
```

Now let's run
```shell
npx drizzle-kit generate --config=./configs/drizzle.config.ts --name=seed-users --custom
```
And it will successfully generate
<Section>
```plaintext {6}
📦 <project root>
 ├ …
 ├ 📂 migrations
 │ ├ 📂 20242409125510_init
 │ └ 📂 20242409125510_seed-users
 └ …
```
```sql
-- ./drizzle/20242409125510_seed-users/migration.sql

INSERT INTO "users" ("name") VALUES('Dan');
INSERT INTO "users" ("name") VALUES('Andrew');
INSERT INTO "users" ("name") VALUES('Dandrew');
```
</Section>


Source: https://orm.drizzle.team/docs/cockroach/drizzle-kit-migrate

import CodeTab from "@mdx/CodeTab.astro";
import CodeTabs from "@mdx/CodeTabs.astro";
import Section from "@mdx/Section.astro";
import Tab from "@mdx/Tab.astro";
import Tabs from "@mdx/Tabs.astro";
import Callout from "@mdx/Callout.astro";
import Prerequisites from "@mdx/Prerequisites.astro";
import Npx from "@mdx/Npx.astro";

# `drizzle-kit migrate`
<Prerequisites>
- Get started with Drizzle and `drizzle-kit` - [read here](/docs/cockroach/get-started)
- Drizzle schema fundamentals - [read here](/docs/cockroach/sql-schema-declaration)
- Database connection basics - [read here](/docs/cockroach/connect-overview)
- Drizzle migrations fundamentals - [read here](/docs/cockroach/migrations)
- Drizzle Kit [overview](/docs/cockroach/kit-overview) and [config file](/docs/cockroach/drizzle-config-file)
- `drizzle-kit generate` command - [read here](/docs/cockroach/drizzle-kit-generate)
</Prerequisites>
<br/>


`drizzle-kit migrate` lets you apply SQL migrations generated by [`drizzle-kit generate`](/docs/cockroach/drizzle-kit-generate). 
It's designed to cover [code first(option 3)](/docs/cockroach/migrations) approach of managing Drizzle migrations. 

<Callout collapsed="How it works under the hood?">
Drizzle Kit `migrate` command triggers a sequence of events:
1. Reads through migration folder and read all `.sql` migration files
2. Connects to the database and fetches entries from drizzle migrations log table
3. Based on previously applied migrations it will decide which new migrations to run
4. Runs SQL migrations and logs applied migrations to drizzle migrations table

<Section>
```plaintext
  ├ 📂 drizzle       
  │ ├ 📂 20242409125510_premium_mister_fear
  │ └ 📂 20242409135510_delicate_professor_xavie
  └ …
```
```plaintext
┌───────────────────────┐                  
│ $ drizzle-kit migrate │                  
└─┬─────────────────────┘                  
  │                                                         ┌──────────────────────────┐                                         
  └ 1. reads migration.sql files in migrations folder       │                          │
    2. fetch migration history from database -------------> │                          │
  ┌ 3. pick previously unapplied migrations <-------------- │         DATABASE         │
  └ 4. apply new migration to the database ---------------> │                          │
                                                            │                          │
                                                            └──────────────────────────┘
[✓] done!        
```
</Section>
</Callout>

`drizzle-kit migrate` command requires you to specify both `dialect` and database connection credentials, 
you can provide them either via [drizzle.config.ts](/docs/cockroach/drizzle-config-file) config file or via CLI options

<CodeTabs items={["With config file", "As CLI options"]}>
<Section>
```ts {5,8}
// drizzle.config.ts
import { defineConfig } from "drizzle-kit";

export default defineConfig({
  dialect: "cockroach",
  schema: "./src/schema.ts",
  dbCredentials: {
    url: "postgresql://user:password@host:port/dbname"
  },
});
```
```shell
npx drizzle-kit migrate
```
</Section>
```shell
npx drizzle-kit migrate --dialect=cockroach --url=postgresql://user:password@host:port/dbname
```
</CodeTabs>

### Applied migrations log in the database
Upon running migrations Drizzle Kit will persist records about successfully applied migrations in your database. 
It will store them in migrations log table named `__drizzle_migrations` in `drizzle` schema.

You can customise both **table** and **schema** of that table via drizzle config file:
```ts filename="drizzle.config.ts" {8-9}
export default defineConfig({
  dialect: "cockroach",
  schema: "./src/schema.ts",
  dbCredentials: {
    url: "postgresql://user:password@host:port/dbname"
  },
  migrations: {
    table: 'my-migrations-table', // `__drizzle_migrations` by default
    schema: 'public', // `drizzle` by default
  },
});
```

### Multiple configuration files in one project
You can have multiple config files in the project, it's very useful when you have multiple database stages or multiple databases on the same project:
<Npx>
  drizzle-kit migrate --config=drizzle-dev.config.ts
  drizzle-kit migrate --config=drizzle-prod.config.ts
</Npx>
```plaintext {5-6}
📦 <project root>
 ├ 📂 drizzle
 ├ 📂 src
 ├ 📜 .env
 ├ 📜 drizzle-dev.config.ts
 ├ 📜 drizzle-prod.config.ts
 ├ 📜 package.json
 └ 📜 tsconfig.json
```

### Extended example
Let's generate SQL migration and apply it to our database using `drizzle-kit generate` and `drizzle-kit migrate` commands

```plaintext
📦 <project root>
 ├ 📂 drizzle
 ├ 📂 src
 │ ├ 📜 schema.ts
 │ └ 📜 index.ts
 ├ 📜 drizzle.config.ts
 └ …
```
<CodeTabs items={["drizzle.config.ts", "src/schema.ts"]}>
```ts
import { defineConfig } from "drizzle-kit";

export default defineConfig({
  dialect: "cockroach",
  schema: "./src/schema.ts",
  dbCredentials: {
    url: "postgresql://user:password@host:port/dbname"
  },
  migrations: {
    table: 'journal', 
    schema: 'drizzle', 
  },
});
```
```ts 
import * as p from "drizzle-orm/cockroach-core";

export const users = p.cockroachTable("users", {
  id: p.int4().primaryKey(),
  name: p.string(),
})
```
</CodeTabs>

Now let's run
```shell
npx drizzle-kit generate --name=init
```
it will generate
<Section>
```plaintext {5}
📦 <project root>
 ├ …
 ├ 📂 migrations
 │ ├ 📂 20242409125510_init
 └ …
```
```sql
-- ./drizzle/0000_init.sql

CREATE TABLE "users" (
	"id" int4 PRIMARY KEY,
	"name" string
);
```
</Section>

Now let's run
```shell
npx drizzle-kit migrate
```

and our SQL migration is now successfully applied to the database ✅


Source: https://orm.drizzle.team/docs/cockroach/drizzle-kit-pull

import CodeTab from "@mdx/CodeTab.astro";
import CodeTabs from "@mdx/CodeTabs.astro";
import Section from "@mdx/Section.astro";
import Tab from "@mdx/Tab.astro";
import Tabs from "@mdx/Tabs.astro";
import Callout from "@mdx/Callout.astro";
import Prerequisites from "@mdx/Prerequisites.astro";
import Drivers from "@mdx/Drivers.mdx"
import Dialects from "@mdx/Dialects.mdx"
import Npm from "@mdx/Npm.astro"
import Npx from "@mdx/Npx.astro"

# `drizzle-kit pull`

<Prerequisites>
- Get started with Drizzle and `drizzle-kit` - [read here](/docs/cockroach/get-started)
- Drizzle schema fundamentals - [read here](/docs/cockroach/sql-schema-declaration) 
- Database connection basics - [read here](/docs/cockroach/connect-overview) 
- Drizzle migrations fundamentals - [read here](/docs/cockroach/migrations) 
- Drizzle Kit [overview](/docs/cockroach/kit-overview) and [config file](/docs/cockroach/drizzle-config-file) docs
</Prerequisites>

`drizzle-kit pull` lets you literally pull(introspect) your existing database schema and generate `schema.ts` drizzle schema file, 
it is designed to cover [database first](/docs/cockroach/migrations) approach of Drizzle migrations.

<Callout collapsed="How it works under the hood?">
When you run Drizzle Kit `pull` command it will:
1. Pull database schema(DDL) from your existing database
2. Generate `schema.ts` drizzle schema file and save it to `out` folder

<Section>
```
                                  ┌────────────────────────┐      ┌─────────────────────────┐ 
                                  │                        │ <---  CREATE TABLE "users" (
┌──────────────────────────┐      │                        │       	"id" int4 PRIMARY KEY,
│ ~ drizzle-kit pull       │      │                        │       	"name" string,
└─┬────────────────────────┘      │                        │       	"email" string unique
  │                               │        DATABASE        │       );
  │                               │                        │
  └ Pull datatabase schema -----> │                        │
  ┌ Generate Drizzle       <----- │                        │
  │ schema TypeScript file        └────────────────────────┘
  │
  v
```
```typescript
import * as p from "drizzle-orm/cockroach-core";

export const users = p.cockroachTable("users", {
    id: p.int4().primaryKey(),
    name: p.string(),
    email: p.string(),
  },
  (table) => [p.uniqueIndex('users_email_key').using('btree', table.email.asc())],
);
```
</Section>
</Callout>

It is a great approach if you need to manage database schema outside of your TypeScript project or 
you're using database, which is managed by somebody else.

<br/>
<hr/>
<br/>

`drizzle-kit pull` requires you to specify `dialect` and either
database connection `url` or `user:password@host:port/db` params, you can provide them
either via [drizzle.config.ts](/docs/cockroach/drizzle-config-file) config file or via CLI options:

<CodeTabs items={["With config file", "With CLI options"]}>
<Section>
```ts
// drizzle.config.ts
import { defineConfig } from "drizzle-kit";

export default defineConfig({
  dialect: "cockroach",
  dbCredentials: {
    url: "postgresql://user:password@host:port/dbname",
  },
});
```
```shell
npx drizzle-kit pull
```
</Section>

```shell
npx drizzle-kit pull --dialect=cockroach --url=postgresql://user:password@host:port/dbname
```
</CodeTabs>

### Multiple configuration files in one project

You can have multiple config files in the project, it's very useful when you have multiple database stages or multiple databases or different databases on the same project:

<Npx>
  drizzle-kit pull --config=drizzle-dev.config.ts
  drizzle-kit pull --config=drizzle-prod.config.ts
</Npx>
```plaintext {5-6}
📦 <project root>
 ├ 📂 drizzle
 ├ 📂 src
 ├ 📜 .env
 ├ 📜 drizzle-dev.config.ts
 ├ 📜 drizzle-prod.config.ts
 ├ 📜 package.json
 └ 📜 tsconfig.json
```

### Specifying database driver
Drizzle Kit does not come with a pre-bundled database driver, 
it will automatically pick available database driver from your current project based on the `dialect` - [see discussion](https://github.com/drizzle-team/drizzle-orm/discussions/2203).

### Initial pull

You can use the `--init` flag to mark the pulled schema as an applied migration in your database, 
so that all subsequent migrations are diffed against the initial one

```shell
npx drizzle-kit pull --init
```

### Including tables, schemas and extensions
`drizzle-kit pull` will by default manage all tables in all schemas.
You can configure list of tables, schemas and extensions via `tablesFilters`, `schemaFilter` and `extensionFilters` options.

|                     |                                                                                               |
| :------------------ | :-------------------------------------------------------------------------------------------- |
| `tablesFilter`      | `glob` based table names filter, e.g. `["users", "user_info"]` or `"user*"`. Default is `"*"` |
| `schemaFilter`      | `glob` based schema names filter, e.g. `["public", "drizzle"]` or `"drizzle*"`. Default is `"*"`                     |
<br/>

Let's configure drizzle-kit to only operate with **all tables** in **public** schema
and let drizzle-kit know that there's a **postgis** extension installed, 
which creates it's own tables in public schema, so drizzle can ignore them.

<Section>
```ts filename="drizzle.config.ts" {9-11}
import { defineConfig } from "drizzle-kit";

export default defineConfig({
  dialect: "cockroach",
  schema: "./src/schema.ts",
  dbCredentials: {
    url: "postgresql://user:password@host:port/dbname",
  },
  schemaFilter: ["public"],
  tablesFilter: ["*"],
});
```
```shell
npx drizzle-kit pull
```
</Section>

### Extended list of configurations
We recommend configuring `drizzle-kit` through [drizzle.config.ts](/docs/cockroach/drizzle-config-file) file, 
yet you can provide all configuration options through CLI if necessary, e.g. in CI/CD pipelines, etc.

|                     |            |                                                                           |
| :------------------ | :--------- | :------------------------------------------------------------------------ |
| `dialect`           | `required` | Database dialect, one of <Dialects/>                                      |
| `driver`            |            | Drivers exceptions <Drivers/>                                             |
| `out`               |            | Migrations output folder path, default is `./drizzle`                     |
| `url`               |            | Database connection string                                                |
| `user`              |            | Database user                                                             |
| `password`          |            | Database password                                                         |
| `host`              |            | Host                                                                      |
| `port`              |            | Port                                                                      |
| `database`          |            | Database name                                                             |
| `config`            |            | Configuration file path, default is `drizzle.config.ts`                          |
| `introspect-casing` |            | Strategy for JS keys creation in columns, tables, etc. `preserve` `camel` |
| `tablesFilter`      |            | Table name filter                                                         |
| `schemaFilter`      |            | Schema name filter. Default: `["*"]`                                 |

<Npx>
drizzle-kit pull --dialect=cockroach --url=postgresql://user:password@host:port/dbname
drizzle-kit pull --dialect=cockroach --driver=pglite url=database/
drizzle-kit pull --dialect=cockroach --tablesFilter='user*' url=postgresql://user:password@host:port/dbname
</Npx>

{/* TODO update gif */}
![](@/assets/gifs/introspect_mysql.gif)


Source: https://orm.drizzle.team/docs/cockroach/drizzle-kit-push

import CodeTab from "@mdx/CodeTab.astro";
import CodeTabs from "@mdx/CodeTabs.astro";
import Section from "@mdx/Section.astro";
import Tab from "@mdx/Tab.astro";
import Tabs from "@mdx/Tabs.astro";
import Callout from "@mdx/Callout.astro";
import Prerequisites from "@mdx/Prerequisites.astro";
import Npx from "@mdx/Npx.astro";
import SchemaFilePaths from "@mdx/SchemaFilePaths.mdx";
import Drivers from "@mdx/Drivers.mdx"
import Dialects from "@mdx/Dialects.mdx"
import DriversExamples from "@mdx/DriversExamples.mdx"

# `drizzle-kit push`

<Prerequisites>
- Get started with Drizzle and `drizzle-kit` - [read here](/docs/cockroach/get-started)
- Drizzle schema fundamentals - [read here](/docs/cockroach/sql-schema-declaration) 
- Database connection basics - [read here](/docs/cockroach/connect-overview) 
- Drizzle migrations fundamentals - [read here](/docs/cockroach/migrations) 
- Drizzle Kit [overview](/docs/cockroach/kit-overview) and [config file](/docs/cockroach/drizzle-config-file) docs
</Prerequisites>


`drizzle-kit push` lets you literally push your schema and subsequent schema changes directly to the
database while omitting SQL files generation, it's designed to cover [code first](/docs/cockroach/migrations)
approach of Drizzle migrations.

<Callout collapsed="How it works under the hood?">
When you run Drizzle Kit `push` command it will:
1. Read through your Drizzle schema file(s) and compose a json snapshot of your schema
2. Pull(introspect) database schema 
3. Based on differences between those two it will generate SQL migrations
4. Apply SQL migrations to the database

<Section>
```typescript filename="src/schema.ts"
import * as p from "drizzle-orm/cockroach-core";

export const users = p.cockroachTable("users", {
  id: p.int4().primaryKey(),
  name: p.string(),
});
```
```
┌─────────────────────┐                  
│ ~ drizzle-kit push  │                  
└─┬───────────────────┘                  
  │                                           ┌──────────────────────────┐
  └ Pull current datatabase schema ---------> │                          │
                                              │                          │
  ┌ Generate alternations based on diff <---- │         DATABASE         │
  │                                           │                          │
  └ Apply migrations to the database -------> │                          │
                                       │      └──────────────────────────┘
                                       │
  ┌───────────────────────────────────────────┴────────────────┐
   CREATE TABLE "users" ("id" int4 PRIMARY KEY, "name" string);
```
</Section>
</Callout>

It's the best approach for rapid prototyping and we've seen dozens of teams
and solo developers successfully using it as a primary migrations flow in their production applications.
It pairs exceptionally well with blue/green deployment strategy and serverless databases like
[Planetscale](https://planetscale.com), [Neon](https://neon.tech), [Turso](https://turso.tech/drizzle) and others.

<br/>
<hr/>
<br/>


`drizzle-kit push` requires you to specify `dialect`, path to the `schema` file(s) and either
database connection `url` or `user:password@host:port/db` params, you can provide them
either via [drizzle.config.ts](/docs/cockroach/drizzle-config-file) config file or via CLI options:

<CodeTabs items={["With config file", "With CLI options"]}>
<Section>
```ts
// drizzle.config.ts
import { defineConfig } from "drizzle-kit";

export default defineConfig({
  dialect: "cockroach",
  schema: "./src/schema.ts",
  dbCredentials: {
    url: "postgresql://user:password@host:port/dbname",
  },
});
```
```shell
npx drizzle-kit push
```
</Section>

```shell
npx drizzle-kit push --dialect=cockroach --schema=./src/schema.ts --url=postgresql://user:password@host:port/dbname
```

</CodeTabs>

### Schema files path

You can have a single `schema.ts` file or as many schema files as you want spread out across the project.
Drizzle Kit requires you to specify path(s) to them as a [glob](https://www.digitalocean.com/community/tools/glob?comments=true&glob=/**/*.js&matches=false&tests=//%20This%20will%20match%20as%20it%20ends%20with%20'.js'&tests=/hello/world.js&tests=//%20This%20won't%20match!&tests=/test/some/globs) via `schema` configuration option.

<SchemaFilePaths />

### Multiple configuration files in one project

You can have multiple config files in the project, it's very useful when you have multiple database stages or multiple databases or different databases on the same project:

<Npx>
  drizzle-kit push --config=drizzle-dev.config.ts
  drizzle-kit push --config=drizzle-prod.config.ts
</Npx>
```plaintext {5-6}
📦 <project root>
 ├ 📂 drizzle
 ├ 📂 src
 ├ 📜 .env
 ├ 📜 drizzle-dev.config.ts
 ├ 📜 drizzle-prod.config.ts
 ├ 📜 package.json
 └ 📜 tsconfig.json
```

### Specifying database driver
Drizzle Kit does not come with a pre-bundled database driver, 
it will automatically pick an available database driver from your current project based on the `dialect` - [see discussion](https://github.com/drizzle-team/drizzle-orm/discussions/2203).



### Including tables and schemas 
`drizzle-kit push` will manage all tables and schemas by default.
You can configure list of tables, schemas via `tablesFilter` and `schemaFilter` options.

|                     |                                                                                               |
| :------------------ | :-------------------------------------------------------------------------------------------- |
| `tablesFilter`      | `glob` based table names filter, e.g. `["users", "user_info"]` or `"user*"`. Default is `"*"` |
| `schemaFilter`      | Schema names filter, e.g. `["public", "drizzle"]`. Default is "*"                       |
<br/>

Let's configure drizzle-kit to only operate with **all tables** in **public** schema
and let drizzle-kit know that there's a **postgis** extension installed, 
which creates it's own tables in public schema, so drizzle can ignore them.

<Section>
```ts filename="drizzle.config.ts" {9-10}
import { defineConfig } from "drizzle-kit";

export default defineConfig({
  dialect: "cockroach",
  schema: "./src/schema.ts",
  dbCredentials: {
    url: "postgresql://user:password@host:port/dbname",
  },
  schemaFilter: ["public"],
  tablesFilter: ["*"],
});
```
```shell
npx drizzle-kit push
```
</Section>

### Extended list of configurations

`drizzle-kit push` has a list of cli-only options

<rem025/>

|           |                                                                 |
| :-------- | :---------------------------------------------------------------|
| `verbose` | print all SQL statements prior to execution                     |
| `explain` | print the planned SQL changes, without applying them (dry run)  |
| `force`   | auto-accept all data-loss statements                            |
<br/>
<Npx>
drizzle-kit push --explain --verbose --force
</Npx>

<br/>
<hr/>
<br/>
We recommend configuring `drizzle-kit` through [drizzle.config.ts](/docs/cockroach/drizzle-config-file) file, 
yet you can provide all configuration options through CLI if necessary, e.g. in CI/CD pipelines, etc.

|                     |            |                                                                           |
| :------------------ | :--------- | :------------------------------------------------------------------------ |
| `dialect`           | `required` | Database dialect, one of <Dialects/>                                      |
| `schema`            | `required` | Path to typescript schema file(s) or folder(s) with multiple schema files |
| `tablesFilter`      |            | Table name filter                                                         |
| `schemaFilter`      |            | Schema name filter. Default: `["*"]`                                 |
| `url`               |            | Database connection string                                                |
| `user`              |            | Database user                                                             |
| `password`          |            | Database password                                                         |
| `host`              |            | Host                                                                      |
| `port`              |            | Port                                                                      |
| `database`          |            | Database name                                                             |
| `config`            |            | Configuration file path, default=`drizzle.config.ts`                             |

<Npx>
drizzle-kit push dialect=cockroach schema=src/schema.ts url=postgresql://user:password@host:port/dbname
drizzle-kit push dialect=cockroach schema=src/schema.ts driver=pglite url=database/
drizzle-kit push dialect=cockroach schema=src/schema.ts --tablesFilter='user*' url=postgresql://user:password@host:port/dbname
</Npx>


### Extended example
Let's declare drizzle schema in the project and push it to the database via `drizzle-kit push` command

```plaintext
📦 <project root>
 ├ 📂 src
 │ ├ 📜 schema.ts
 │ └ 📜 index.ts
 ├ 📜 drizzle.config.ts
 └ …
```
<CodeTabs items={["drizzle.config.ts", "src/schema.ts"]}>
```ts
import { defineConfig } from "drizzle-kit";

export default defineConfig({
  dialect: "cockroach",
  schema: "./src/schema.ts",
  dbCredentials: {
    url: "postgresql://user:password@host:port/dbname"
  },
});
```
```ts 
import * as p from "drizzle-orm/cockroach-core";

export const users = p.cockroachTable("users", {
  id: p.int4().primaryKey(),
  name: p.string(),
})
```
</CodeTabs>

Now let's run
```shell
npx drizzle-kit push
```

it will pull existing(empty) schema from the database and generate SQL migration and apply it under the hood
```sql
CREATE TABLE "users" (
	"id" int4 PRIMARY KEY,
	"name" string
);
```

DONE ✅


Source: https://orm.drizzle.team/docs/cockroach/drizzle-kit-studio

import CodeTab from "@mdx/CodeTab.astro";
import CodeTabs from "@mdx/CodeTabs.astro";
import Section from "@mdx/Section.astro";
import Tab from "@mdx/Tab.astro";
import Tabs from "@mdx/Tabs.astro";
import Callout from "@mdx/Callout.astro";
import Prerequisites from "@mdx/Prerequisites.astro";
import Npm from "@mdx/Npm.astro";
import Npx from "@mdx/Npx.astro";


# `drizzle-kit studio`
<Prerequisites>
- Drizzle Kit [overview](/docs/cockroach/kit-overview) and [config file](/docs/cockroach/drizzle-config-file)
- Drizzle Studio, our database browser - [read here](/drizzle-studio/overview)
</Prerequisites>

`drizzle-kit studio` command spins up a server for [Drizzle Studio](/drizzle-studio/overview) hosted on [local.drizzle.studio](https://local.drizzle.studio). 
It requires you to specify database connection credentials via [drizzle.config.ts](/docs/cockroach/drizzle-config-file) config file.

By default it will start a Drizzle Studio server on `127.0.0.1:4983`
<Section>
```ts {6}
// drizzle.config.ts
import { defineConfig } from "drizzle-kit";

export default defineConfig({
  dialect: "cockroach",
  dbCredentials: {
    url: "postgresql://user:password@host:port/dbname"
  },
});
```
```shell
npx drizzle-kit studio
```
</Section>

### Configuring `host` and `port`
By default Drizzle Studio server starts on `127.0.0.1:4983`, 
you can config `host` and `port` via CLI options

<Npx>
drizzle-kit studio --port=3000
drizzle-kit studio --host=0.0.0.0
drizzle-kit studio --host=0.0.0.0 --port=3000
</Npx>


### Logging
You can enable logging of every SQL statement by providing `verbose` flag

<Npx>
drizzle-kit studio --verbose
</Npx>

### Safari and Brave support
Safari and Brave block access to localhost by default. 
You need to install [mkcert](https://github.com/FiloSottile/mkcert) and generate self-signed certificate:

1. Follow the mkcert [installation steps](https://github.com/FiloSottile/mkcert#installation)
2. Run `mkcert -install`
3. Restart your `drizzle-kit studio`

### Other flavours of Drizzle Studio
Apart from `drizzle-kit studio` for local development, Drizzle Studio also comes as a self-hosted
Drizzle Gateway, a Chrome extension for serverless database vendors and an embeddable component
for your own product — check out the [Drizzle Studio overview](/drizzle-studio/overview).

### Limitations
Our hosted version Drizzle Studio is meant to be used for local development and not meant to be used on remote (VPS, etc).

If you want to deploy Drizzle Studio to your VPS — that's what
[Drizzle Gateway](/drizzle-studio/overview#drizzle-gateway) is for.

### Is it open source?
No. Drizzle ORM and Drizzle Kit are fully open sourced, while Studio is not. 

Drizzle Studio for local development is free to use forever to enrich Drizzle ecosystem, 
open sourcing one would've break our ability to provide B2B offerings and monetise it, unfortunately.


Source: https://orm.drizzle.team/docs/cockroach/drizzle-kit-up

import CodeTab from "@mdx/CodeTab.astro";
import CodeTabs from "@mdx/CodeTabs.astro";
import Section from "@mdx/Section.astro";
import Tab from "@mdx/Tab.astro";
import Tabs from "@mdx/Tabs.astro";
import Callout from "@mdx/Callout.astro";
import Prerequisites from "@mdx/Prerequisites.astro";
import Npx from "@mdx/Npx.astro";
import Dialects from "@mdx/Dialects.mdx"

# `drizzle-kit up`

<Prerequisites>
- Get started with Drizzle and `drizzle-kit` - [read here](/docs/cockroach/get-started)
- Drizzle schema fundamentals - [read here](/docs/cockroach/sql-schema-declaration)
- Database connection basics - [read here](/docs/cockroach/connect-overview)
- Drizzle migrations fundamentals - [read here](/docs/cockroach/migrations)
- Drizzle Kit [overview](/docs/cockroach/kit-overview) and [config file](/docs/cockroach/drizzle-config-file)
- `drizzle-kit generate` command - [read here](/docs/cockroach/drizzle-kit-generate)
</Prerequisites>

`drizzle-kit up` command lets you upgrade drizzle schema snapshots to a newer version. 
It's required whenever we introduce breaking changes to the json snapshots of the schema and upgrade the internal version.

<br/>
<hr/>
<br/>

`drizzle-kit up` command requires you to specify `dialect` param,
you can provide it either via [drizzle.config.ts](/docs/cockroach/drizzle-config-file) config file or via CLI options

<CodeTabs items={["With config file", "As CLI options"]}>
<Section>
```ts {5,8}
// drizzle.config.ts
import { defineConfig } from "drizzle-kit";

export default defineConfig({
  dialect: "cockroach",
});
```
```shell
npx drizzle-kit up
```
</Section>
```shell
npx drizzle-kit up --dialect=cockroach
```
</CodeTabs>

### Multiple configuration files in one project
You can have multiple config files in the project, it's very useful when you have multiple database stages or multiple databases on the same project:
<Npx>
  drizzle-kit migrate --config=drizzle-dev.config.ts
  drizzle-kit migrate --config=drizzle-prod.config.ts
</Npx>
```plaintext {5-6}
📦 <project root>
 ├ 📂 drizzle
 ├ 📂 src
 ├ 📜 .env
 ├ 📜 drizzle-dev.config.ts
 ├ 📜 drizzle-prod.config.ts
 ├ 📜 package.json
 └ 📜 tsconfig.json
```

### Extended list of configurations
We recommend configuring `drizzle-kit` through [drizzle.config.ts](/docs/cockroach/drizzle-config-file) file, 
yet you can provide all configuration options through CLI if necessary, e.g. in CI/CD pipelines, etc.
<rem025/>
|           |            |                                                                         |
| :-------- | :--------- | :---------------------------------------------------------------------- |
| `dialect` | `required` | Database dialect you are using. Can be one of <Dialects/> |
| `out`     |            | Migrations folder, default=`./drizzle`                                  |
| `config`  |            | Configuration file path, default=`drizzle.config.ts`                           |
<br/>
<Npx>
drizzle-kit up --dialect=cockroach
drizzle-kit up --dialect=cockroach --out=./migrations-folder
</Npx>

{/* TODO: update up gif */}
![](@/assets/gifs/up_mysql.gif)



Source: https://orm.drizzle.team/docs/cockroach/dynamic-query-building-copy

import Callout from '@mdx/Callout.astro';

# Dynamic query building

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
```

In the previous ORM versions, when such restrictions weren't implemented, this example in particular was a source of confusion for many users, as they expected the query builder to "merge" multiple `.where()` calls into a single condition.

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 = 1,
	pageSize: number = 10,
) {
	return qb.limit(pageSize).offset((page - 1) * 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);
```

This is possible, because `PgSelect` and other similar types are specifically designed to be used in dynamic query building. They can only be used in dynamic mode.

Here is the list of all types that can be used as generic parameters in dynamic query building:

{

<table>
	<thead align='center'>
		<tr>
			<td>
				<b>Dialect</b>
			</td>
			<td colspan='4'>
				<b>Type</b>
			</td>
		</tr>
		<tr>
			<td>
				<b>Query</b>
			</td>
			<td>
				<b>Select</b>
			</td>
			<td>
				<b>Insert</b>
			</td>
			<td>
				<b>Update</b>
			</td>
			<td>
				<b>Delete</b>
			</td>
		</tr>
	</thead>
	<tbody>
		<tr align='center'>
			<td rowspan='2'>Postgres</td>
			<td>
				<code>PgSelect</code>
			</td>
			<td rowspan='2'>
				<code>PgInsert</code>
			</td>
			<td rowspan='2'>
				<code>PgUpdate</code>
			</td>
			<td rowspan='2'>
				<code>PgDelete</code>
			</td>
		</tr>
		<tr align='center'>
			<td>
				<code>PgSelectQueryBuilder</code>
			</td>
		</tr>
		<tr align='center'>
			<td rowspan='2'>MySQL</td>
			<td>
				<code>MySqlSelect</code>
			</td>
			<td rowspan='2'>
				<code>MySqlInsert</code>
			</td>
			<td rowspan='2'>
				<code>MySqlUpdate</code>
			</td>
			<td rowspan='2'>
				<code>MySqlDelete</code>
			</td>
		</tr>
		<tr align='center'>
			<td>
				<code>MySqlSelectQueryBuilder</code>
			</td>
		</tr>
		<tr align='center'>
			<td rowspan='2'>SQLite</td>
			<td>
				<code>SQLiteSelect</code>
			</td>
			<td rowspan='2'>
				<code>SQLiteInsert</code>
			</td>
			<td rowspan='2'>
				<code>SQLiteUpdate</code>
			</td>
			<td rowspan='2'>
				<code>SQLiteDelete</code>
			</td>
		</tr>
		<tr align='center'>
			<td>
				<code>SQLiteSelectQueryBuilder</code>
			</td>
		</tr>
	</tbody>
</table>

}

<Callout type='info'>
	The `...QueryBuilder` types are for usage with [standalone query builder
	instances](/docs/goodies#standalone-query-builder). DB query builders are
	subclasses of them, so you can use them as well.

    ```ts
    	import { QueryBuilder } from 'drizzle-orm/pg-core';

    	function withFriends<T extends PgSelectQueryBuilder>(qb: T) {
    		return qb.leftJoin(friends, eq(friends.userId, users.id));
    	}

    	const qb = new QueryBuilder();
    	let query = qb.select().from(users).where(eq(users.id, 1)).$dynamic();
    	query = withFriends(query);
    ```

</Callout>


Source: https://orm.drizzle.team/docs/cockroach/dynamic-query-building

import Callout from '@mdx/Callout.astro';

# Dynamic query building

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
```

In the previous ORM versions, when such restrictions weren't implemented, this example in particular was a source of confusion for many users, as they expected the query builder to "merge" multiple `.where()` calls into a single condition.

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 CockroachSelect>(
	qb: T,
	page: number = 1,
	pageSize: number = 10,
) {
	return qb.limit(pageSize).offset((page - 1) * 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 CockroachSelect>(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);
```

This is possible, because `CockroachSelect` and other similar types are specifically designed to be used in dynamic query building. They can only be used in dynamic mode.

Here is the list of all types that can be used as generic parameters in dynamic query building:

| Query  | Type                              |
|:--------|:-----------------------------------|
| Select | `CockroachSelect` / `CockroachSelectQueryBuilder` |
| Insert | `CockroachInsert`                        |
| Update | `CockroachUpdate`                        |
| Delete | `CockroachDelete`                        |

<Callout type='info'>
	The `...QueryBuilder` types are for usage with [standalone query builder
	instances](/docs/cockroach/goodies#standalone-query-builder). DB query builders are
	subclasses of them, so you can use them as well.

    ```ts
    	import { QueryBuilder } from 'drizzle-orm/cockroach-core';

    	function withFriends<T extends CockroachSelectQueryBuilder>(qb: T) {
    		return qb.leftJoin(friends, eq(friends.userId, users.id));
    	}

    	const qb = new QueryBuilder();
    	let query = qb.select().from(users).where(eq(users.id, 1)).$dynamic();
    	query = withFriends(query);
    ```

</Callout>


Source: https://orm.drizzle.team/docs/cockroach/effect-schema

import Npm from '@mdx/Npm.astro';
import Callout from '@mdx/Callout.astro';

# effect-schema

Allows you to generate [effect](https://effect.website/) schemas from Drizzle ORM schemas.

**Features**

- Create a select schema for tables and enums.
- Create insert and update schemas for tables.
- Supported dialect: CockroachDB.

#### Usage

```ts
import { int4, cockroachTable, text, timestamp } from 'drizzle-orm/cockroach-core';
import { createInsertSchema, createSelectSchema, createUpdateSchema } from 'drizzle-orm/effect-schema';
import { Effect, Schema } from 'effect';

const users = cockroachTable('users', {
	id: int4().primaryKey().generatedAlwaysAsIdentity(),
	name: text().notNull(),
	email: text().notNull(),
	role: text({ enum: ['admin', 'user'] }).notNull(),
	createdAt: timestamp('created_at').notNull().defaultNow(),
});

// Schema for inserting a user - can be used to validate API requests
const UserInsert = createInsertSchema(users);

// Schema for updating a user - can be used to validate API requests
const UserUpdate = createUpdateSchema(users);

// Schema for selecting a user - can be used to validate API responses
const UserSelect = createSelectSchema(users);

// Overriding the fields
const UserInsert = createInsertSchema(users, {
	role: Schema.String,
});

// Refining the fields - useful if you want to change the fields before they become nullable/optional in the final schema
const UserInsert = createInsertSchema(users, {
	id: (schema) => schema.check(Schema.isGreaterThanOrEqualTo(0)),
	role: Schema.String,
});

// Usage

const program = Effect.gen(function*() {
	const parsedUser = yield* Schema.decodeUnknownEffect(UserInsert)({
		name: 'John Doe',
		email: 'johndoe@test.com',
		role: 'admin',
	});
});
```

Source: https://orm.drizzle.team/docs/cockroach/extensions


import Callout from '@mdx/Callout.astro';

<Callout>
Currently, there are no Cockroach extensions natively supported by Drizzle. Once those are added, we will have them here!
</Callout>

Source: https://orm.drizzle.team/docs/cockroach/generated-columns

import CodeTabs from '@mdx/CodeTabs.astro';
import CodeTab from '@mdx/CodeTab.astro';
import Callout from '@mdx/Callout.astro';

# Generated Columns

Stored (or persistent) Generated Columns: These columns are computed when a row is inserted or updated and their values are stored in the database. This allows them to be indexed and can improve query performance since the values do not need to be recomputed for each query.

#### Database side
    **Types**: `STORED` only

    **How It Works**
    - Automatically computes values based on other columns during insert or update.

    **Capabilities**
    - Simplifies data access by precomputing complex expressions.
    - Enhances query performance with index support on generated columns.

    **Limitations**
    - Cannot specify default values.
    - Expressions cannot reference other generated columns or include subqueries.
    - Schema changes required to modify generated column expressions.
    - Cannot directly use in primary keys, foreign keys, or unique constraints   

    For more info, please check [CockroachDB](https://www.cockroachlabs.com/docs/stable/computed-columns) docs 

    #### Drizzle side
    In Drizzle you can specify `.generatedAlwaysAs()` function on any column type and add a supported sql query, 
    that will generate this column data for you.

    #### Features 
    This function can accept generated expression in 2 ways:

    **`sql`** tag - if you want drizzle to escape some values for you

    <CodeTab>
    ```ts
    export const test = cockroachTable("test", {
        generatedName: string("gen_name").generatedAlwaysAs(sql`'hello "world"!'`),
    });
    ```
    ```sql
    CREATE TABLE "test" (
	    "gen_name" text GENERATED ALWAYS AS ('hello "world"!') STORED
    );
    ```
    </CodeTab>

    **`callback`** - if you need to reference columns from a table
    <CodeTab>
    ```ts
    export const test = cockroachTable("test", {
        name: string("first_name"),
        generatedName: string("gen_name").generatedAlwaysAs(
          (): SQL => sql`'hi, ' || ${test.name} || '!'`
        ),
    });
    ```
    ```sql
    CREATE TABLE "test" (
	        "first_name" string,
	        "gen_name" string GENERATED ALWAYS AS ('hi, ' || "test"."first_name" || '!') STORED
    );
    ```
    </CodeTab>

    **Example** generated columns with full-text search
   <CodeTabs items={["schema.ts"]}>
	<CodeTab>
	```typescript copy {17-19}
    import { SQL, sql } from "drizzle-orm";
    import { customType, index, int4, cockroachTable, string } from "drizzle-orm/cockroach-core";

    const tsVector = customType<{ data: string }>({
      dataType() {
        return "tsvector";
      },
    });

    export const test = cockroachTable(
      "test",
      {
        id: int4("id").primaryKey().generatedAlwaysAsIdentity(),
        content: string("content"),
        contentSearch: tsVector("content_search", {
          dimensions: 3,
        }).generatedAlwaysAs(
          (): SQL => sql`to_tsvector('english', ${test.content})`
        ),
      },
      (t) => [
        index("idx_content_search").using("gin", t.contentSearch)
      ]
    );
    ```
    ```sql {4}
    CREATE TABLE "test" (
            "id" int4 PRIMARY KEY GENERATED ALWAYS AS IDENTITY (INCREMENT BY 1 MINVALUE 1 MAXVALUE 2147483647 START WITH 1 CACHE 1),
            "content" string,
            "content_search" tsvector GENERATED ALWAYS AS (to_tsvector('english', "test"."content")) STORED
    );

    CREATE INDEX "idx_content_search" ON "test" USING gin ("content_search");
    ```
    </CodeTab>
   </CodeTabs>


Source: https://orm.drizzle.team/docs/cockroach/get-started-cockroach

import Tab from '@mdx/Tab.astro';
import Tabs from '@mdx/Tabs.astro';
import Npm from "@mdx/Npm.astro";
import Callout from '@mdx/Callout.astro';
import Steps from '@mdx/Steps.astro';
import AnchorCards from '@mdx/AnchorCards.astro';
import Prerequisites from "@mdx/Prerequisites.astro";
import CodeTabs from "@mdx/CodeTabs.astro";
import WhatsNextCockroach from "@mdx/WhatsNextCockroach.astro";

# Drizzle \<\> CockroachDB

<br/>

<Prerequisites>
- Database [connection basics](/docs/cockroach/connect-overview) with Drizzle
- node-postgres [basics](https://node-postgres.com/)
</Prerequisites>

Drizzle has native support for CockroachDB connections with the `node-postgres` driver.

#### Step 1 - Install packages
<Npm>
drizzle-orm@rc pg
-D drizzle-kit@rc @types/pg
</Npm>

#### Step 2 - Initialize the driver and make a query
<CodeTabs items={["node-postgres", "node-postgres with config"]}>
```typescript copy
// Make sure to install the 'pg' package 
import { drizzle } from 'drizzle-orm/cockroach';

const db = drizzle(process.env.DATABASE_URL);
 
const result = await db.execute('select 1');
```
```typescript copy
// Make sure to install the 'pg' package 
import { drizzle } from 'drizzle-orm/cockroach';

// You can specify any property from the node-postgres connection options
const db = drizzle({ 
  connection: { 
    connectionString: process.env.DATABASE_URL,
    ssl: true
  }
});
 
const result = await db.execute('select 1');
```
</CodeTabs>

If you need to provide your existing driver:

```typescript copy
// Make sure to install the 'pg' package 
import { drizzle } from "drizzle-orm/cockroach";
import { Pool } from "pg";

const pool = new Pool({
  connectionString: process.env.DATABASE_URL,
});
const db = drizzle({ client: pool });
 
const result = await db.execute('select 1');
```

#### What's next?

<WhatsNextCockroach/>


Source: https://orm.drizzle.team/docs/cockroach/goodies

import Callout from '@mdx/Callout.astro';
import CodeTabs from '@mdx/CodeTabs.astro';

## Type API
Use Drizzle's type helpers to infer `select` and `insert` models from a CockroachDB table schema.

```ts
import { string, int4, cockroachTable } from 'drizzle-orm/cockroach-core';
import { type InferSelectModel, type InferInsertModel } from 'drizzle-orm';

const users = cockroachTable('users', {
  id: int4('id').primaryKey(),
  name: string('name').notNull(),
});

type SelectUser = typeof users.$inferSelect;
type InsertUser = typeof users.$inferInsert;

type SelectUserAlt = InferSelectModel<typeof users>;
type InsertUserAlt = InferInsertModel<typeof users>;
```

## Logging
Enable default query logging by passing `{ logger: true }` to `drizzle`.

```ts
import { drizzle } from "drizzle-orm/cockroach";

const db = drizzle(process.env.DB_URL, { logger: true });
```

You can change the logs destination by creating a `DefaultLogger` instance and providing a custom `writer` to it:
```typescript copy
import { DefaultLogger, type LogWriter } from "drizzle-orm/logger";
import { drizzle } from "drizzle-orm/...";

class MyLogWriter implements LogWriter {
  write(message: string) {
    // Write to file, stdout, etc.
  }
}

const logger = new DefaultLogger({ writer: new MyLogWriter() });
const db = drizzle(process.env.DB_URL, { logger });
```

You can also provide a custom logger.

```ts
import type { Logger } from 'drizzle-orm/logger';
import { drizzle } from "drizzle-orm/cockroach";

class MyLogger implements Logger {
  logQuery(query: string, params: unknown[]): void {
    console.log({ query, params });
  }
}

const db = drizzle(process.env.DB_URL, { logger: new MyLogger() });
```

## Multi-project schema
Use `cockroachTableCreator` to customize table names when several projects share one database.

```ts
import { int4, string, cockroachTableCreator } from 'drizzle-orm/cockroach-core';

const cockroachTable = cockroachTableCreator((name) => `project1_${name}`);

export const users = cockroachTable('users', {
  id: int4().primaryKey(),
  name: string().notNull(),
});
```

```ts
import { defineConfig } from 'drizzle-kit';

export default defineConfig({
  schema: './src/schema/*',
  out: './drizzle',
  dialect: 'cockroach',
  dbCredentials: {
    url: process.env.DATABASE_URL!,
  },
  tablesFilter: ['project1_*'],
});
```
```sql
CREATE TABLE "project1_users" (
        "id" int4 PRIMARY KEY,
        "name" string NOT NULL
);
```

## Printing SQL Query
Print generated SQL from a query with `.toSQL()`.

```ts
const query = db
  .select({ id: users.id, name: users.name })
  .from(users)
  .groupBy(users.id)
  .toSQL();
```

## Raw SQL Queries
Use `db.execute` for raw parametrized SQL.

```ts
import { sql } from 'drizzle-orm';

const statement = sql`select * from ${users} where ${users.id} = ${userId}`;
const result = await db.execute(statement);
```

## Standalone Query Builder
Use the CockroachDB query builder without creating a database instance.

```ts
import { QueryBuilder } from 'drizzle-orm/cockroach-core';

const qb = new QueryBuilder();
const query = qb.select().from(users).where(eq(users.name, 'Dan'));
const { sql, params } = query.toSQL();
```

## Get Typed Columns
Use `getColumns` to get a typed column map, which is useful when excluding fields from a selection.

<CodeTabs items={["index.ts", "schema.ts"]}>
```ts
import { getColumns } from 'drizzle-orm';
import { users } from './schema';

const { password, role, ...rest } = getColumns(users);

await db.select({ ...rest }).from(users);
```
```ts
import { int4, string, pgTable } from "drizzle-orm/pg-core";

export const user = pgTable("user", {
  id: int4().primaryKey(),
  name: string(),
  email: string(),
  password: string(),
  role: string().$type<"admin" | "customer">(),
});
```
</CodeTabs>

## Get Table Information
Use `getTableConfig` to inspect CockroachDB table metadata.

```ts
import { getTableConfig, cockroachTable } from 'drizzle-orm/cockroach-core';

export const table = cockroachTable(...);

const { columns, indexes, foreignKeys, checks, primaryKeys, name, schema } =
  getTableConfig(table);
```

## Compare Object Types
Use `is()` instead of `instanceof` to check Drizzle object types.

```ts
import { Column, is } from 'drizzle-orm';

if (is(value, Column)) {
  // value is narrowed to Column
}
```

## Mock Driver
Use `drizzle.mock()` when you need a typed database object without a real CockroachDB connection.

```ts
import { drizzle } from 'drizzle-orm/node-postgres';
import * as schema from './schema';

const db = drizzle.mock({ schema });
```


Source: https://orm.drizzle.team/docs/cockroach/indexes-constraints

import Callout from '@mdx/Callout.astro';
import Section from '@mdx/Section.astro';

# Indexes & Constraints

## Constraints

SQL constraints are the rules enforced on table columns. They are used to prevent invalid data from being entered into the database.

This ensures the accuracy and reliability of your data in the database.

### Default

The `DEFAULT` clause specifies a default value to use for the column if no value provided by the user when doing an `INSERT`.
If there is no explicit `DEFAULT` clause attached to a column definition,
then the default value of the column is `NULL`.

An explicit `DEFAULT` clause may specify that the default value is `NULL`,
a string constant, a blob constant, a signed-number, or any constant expression enclosed in parentheses.

<Section>
    ```typescript
    import { sql } from "drizzle-orm";
    import { int4, uuid, cockroachTable } from "drizzle-orm/cockroach-core";

    export const table = cockroachTable('table', {
      integer1: int4().default(42),
      integer2: int4().default(sql`24`),
      uuid1: uuid().defaultRandom(),
      uuid2: uuid().default(sql`gen_random_uuid()`),
    });
    ```

    ```sql
    CREATE TABLE "table" (
      "integer1" int4 DEFAULT 42,
      "integer2" int4 DEFAULT 24,
      "uuid1" uuid DEFAULT gen_random_uuid(),
      "uuid2" uuid DEFAULT gen_random_uuid()
    );
    ```
    </Section>

### Not null

By default, a column can hold **NULL** values. The `NOT NULL` constraint enforces a column to **NOT** accept **NULL** values.  

This enforces a field to always contain a value, which means that you cannot insert a new record,
or update a record without adding a value to this field.

<Section>
      ```typescript copy
      import { int4, cockroachTable } from "drizzle-orm/cockroach-core";

      export const table = cockroachTable('table', {
        int4: int4().notNull(),
      });
      ```

      ```sql
      CREATE TABLE "table" (
        "int4" int4 NOT NULL
      );
      ```
    </Section>

### Unique

The `UNIQUE` constraint ensures that all values in a column are different.  

Both the `UNIQUE` and `PRIMARY KEY` constraints provide a guarantee for uniqueness for a column or set of columns.

A `PRIMARY KEY` constraint automatically has a `UNIQUE` constraint.  

<Callout type="info" emoji="ℹ️">
  You can have many `UNIQUE` constraints per table, but only one `PRIMARY KEY` constraint per table.
</Callout>

<Section>
      ```typescript copy
      import { int4, string, unique, cockroachTable } from "drizzle-orm/cockroach-core";

      export const user = cockroachTable('user', {
        id: int4().unique(),
      });

      export const table = cockroachTable('table', {
        id: int4().unique('custom_name'),
      });

      export const composite = cockroachTable('composite_example', {
        id: int4(),
        name: string(),
      }, (t) => [
        unique().on(t.id, t.name),
        unique('custom_name').on(t.id, t.name)
      ]);

      ```

      ```sql
	CREATE TABLE "user" (
		"id" int4 UNIQUE
	);

	CREATE TABLE "table" (
		"id" int4 CONSTRAINT "custom_name" UNIQUE
	);
	
	CREATE TABLE "composite_example" (
		"id" int4,
		"name" string,
		CONSTRAINT "composite_example_id_name_unique" UNIQUE("id","name"),
		CONSTRAINT "custom_name" UNIQUE("id","name")
	);
      ```
    </Section>

### Check

The `CHECK` constraint is used to limit the value range that can be placed in a column.

If you define a `CHECK` constraint on a column it will allow only certain values for this column.  

If you define a `CHECK` constraint on a table it can limit the values in certain columns based on values in other columns in the row.

<Section>
      ```typescript copy
      import { sql } from "drizzle-orm";
      import { check, int4, cockroachTable, string, uuid } from "drizzle-orm/cockroach-core";

      export const users = cockroachTable(
        "users",
        {
          id: uuid().defaultRandom().primaryKey(),
          username: string().notNull(),
          age: int4(),
        },
        (table) => [
          check("age_check1", sql`${table.age} > 21`),
        ]
      );
      ```
      ```sql
	  CREATE TABLE "users" (
		"id" uuid PRIMARY KEY DEFAULT gen_random_uuid(),
		"username" string NOT NULL,
		"age" int4,
		CONSTRAINT "age_check1" CHECK ("users"."age" > 21)
	  );
      ```
    </Section>

### Primary Key

The `PRIMARY KEY` constraint uniquely identifies each record in a table.  
Primary keys must contain `UNIQUE` values, and cannot contain `NULL` values.  

A table can have only **ONE** primary key; and in the table, this primary key can consist of single or multiple columns (fields).

<Section>
      ```typescript copy
      import { int4, string, cockroachTable } from "drizzle-orm/cockroach-core";

      export const user = cockroachTable('user', {
        id: int4('id').primaryKey(),
      });

      export const table = cockroachTable('table', {
        id: string('cuid').primaryKey(),
      });
      ```

      ```sql
	  CREATE TABLE "user" (
		"id" int4 PRIMARY KEY
	  );

	  CREATE TABLE "table" (
		"cuid" string PRIMARY KEY
	  );
      ```
    </Section>

### Composite Primary Key

Just like `PRIMARY KEY`, composite primary key uniquely identifies each record in a table using multiple fields.

Drizzle ORM provides a standalone `primaryKey` operator for that:

<Section>
      ```typescript copy {17,19}
      import { int4, string, primaryKey, cockroachTable } from "drizzle-orm/cockroach-core";

      export const user = cockroachTable("user", {
        id: int4("id").primaryKey(),
        name: string("name"),
      });

      export const book = cockroachTable("book", {
        id: int4("id").primaryKey(),
        name: string("name"),
      });

      export const booksToAuthors = cockroachTable("books_to_authors", {
        authorId: int4("author_id"),
        bookId: int4("book_id"),
      }, (table) => [
        primaryKey({ columns: [table.bookId, table.authorId] }),
        // Or PK with custom name
        primaryKey({ name: 'custom_name', columns: [table.bookId, table.authorId] }),
      ]);
      ```

      ```sql {6,9}
      ...

      CREATE TABLE "books_to_authors" (
        "author_id" int4,
        "book_id" int4,
        PRIMARY KEY("book_id","author_id")
      );

      ALTER TABLE "books_to_authors" ADD CONSTRAINT "custom_name" PRIMARY KEY("book_id","author_id");
      ```
    </Section>

### Foreign key

The `FOREIGN KEY` constraint is used to prevent actions that would destroy links between tables.
A `FOREIGN KEY` is a field (or collection of fields) in one table, that refers to the `PRIMARY KEY` in another table.
The table with the foreign key is called the child table, and the table with the primary key is called the referenced or parent table.

Drizzle ORM provides several ways to declare foreign keys.
You can declare them in a column declaration statement:

	```typescript copy {11}
	import { int4, string, cockroachTable } from "drizzle-orm/cockroach-core";

	export const user = cockroachTable("user", {
		id: int4("id").primaryKey(),
		name: string("name"),
	});

	export const book = cockroachTable("book", {
		id: int4("id"),
		name: string("name"),
		authorId: int4("author_id").references(() => user.id)
	});
	```
	```sql {12}
	CREATE TABLE "user" (
		"id" int4 PRIMARY KEY,
		"name" string
	);

	CREATE TABLE "book" (
		"id" int4,
		"name" string,
		"author_id" int4
	);

	ALTER TABLE "book" ADD CONSTRAINT "book_author_id_user_id_fkey" FOREIGN KEY ("author_id") REFERENCES "user"("id");
	```



If you want to do a self reference, due to a TypeScript limitations you will have to either explicitly
set return type for reference callback or use a standalone `foreignKey` operator.

	```typescript copy {6,16-18}
    import { int4, string, foreignKey, cockroachTable, type AnyCockroachColumn } from "drizzle-orm/cockroach-core";

    export const user = cockroachTable("user", {
      id: int4().primaryKey(),
      name: string(),
      parentId: int4("parent_id").references((): AnyCockroachColumn => user.id)
    });

    // or
    export const user = cockroachTable("user", {
      id: int4(),
      name: string(),
      parentId: int4("parent_id"),
    }, (table) => [
      foreignKey({
        columns: [table.parentId],
        foreignColumns: [table.id],
        name: "custom_fk"
      })
    ]);
    ```
	```sql {7}
	CREATE TABLE "user" (
		"id" int4 PRIMARY KEY,
		"name" string,
		"parent_id" int4
	);
	
	ALTER TABLE "user" ADD CONSTRAINT "user_parent_id_user_id_fkey" FOREIGN KEY ("parent_id") REFERENCES "user"("id");
	```

To declare multi-column foreign keys you can use a dedicated `foreignKey` operator:

```typescript copy {15-19}
    import { int4, string, foreignKey, cockroachTable, primaryKey } from "drizzle-orm/cockroach-core";

    export const user = cockroachTable("user", {
      firstName: string("firstName"),
      lastName: string("lastName"),
    }, (table) => [
      primaryKey({ columns: [table.firstName, table.lastName]})
    ]);

    export const profile = cockroachTable("profile", {
      id: int4("id").primaryKey(),
      userFirstName: string("user_first_name"),
      userLastName: string("user_last_name"),
    }, (table) => [
      foreignKey({
        columns: [table.userFirstName, table.userLastName],
        foreignColumns: [user.firstName, user.lastName],
        name: "custom_fk"
      })
    ])
    ```
	```sql {13}
	CREATE TABLE "user" (
		"firstName" string,
		"lastName" string,
		CONSTRAINT "user_pkey" PRIMARY KEY("firstName","lastName")
	);

	CREATE TABLE "profile" (
		"id" int4 PRIMARY KEY,
		"user_first_name" string,
		"user_last_name" string
	);
	
	ALTER TABLE "profile" ADD CONSTRAINT "custom_fk" FOREIGN KEY ("user_first_name","user_last_name") REFERENCES "user"("firstName","lastName");
	```

## Indexes

Drizzle ORM provides API for both `index` and `unique index` declaration:

<Section>
    ```typescript copy {8-9}
    import { int4, string, index, uniqueIndex, cockroachTable } from "drizzle-orm/cockroach-core";

    export const user = cockroachTable("user", {
      id: int4().primaryKey(),
      name: string(),
      email: string(),
    }, (table) => [
      index("name_idx").on(table.name),
      uniqueIndex("email_idx").on(table.email)
    ]);
    ```
    ```sql {3,6}
	CREATE TABLE "user" (
	  ...,
	  CONSTRAINT "email_idx" UNIQUE("email")
	  );

	CREATE INDEX "name_idx" ON "user" ("name");
    ```
</Section>


Drizzle ORM provides a set of params for index creation:

```ts
// `.on()`
index('name')
  .on(table.column1.asc(), ...)
  .where(sql``) // sql expression

// `.onOnly()`
index('name')
  .onOnly(table.column1.asc(), ...)
  .where(sql``) // sql expression

// Second Example, with `.using()`
index('name')
  .using('btree', table.column1.asc(), sql`lower(${table.column2})`)
  .where(sql``) // sql expression
```


Source: https://orm.drizzle.team/docs/cockroach/insert

import Section from '@mdx/Section.astro';
import Callout from '@mdx/Callout.astro';
import Tab from '@mdx/Tab.astro';
import Tabs from '@mdx/Tabs.astro';

# SQL Insert

<Callout type='info'>
All the values provided to `.values()`are parameterized automatically.
For example, this query:
```ts
await db.insert(users).values({ name: 'Andrew' });
```
will be translated to:
```sql
insert into "users" ("id", "name") values (default, $1) -- params: ['Andrew']
```
</Callout>

<br/>

Drizzle ORM provides you the most SQL-like way to insert rows into the database tables.

Inserting data with Drizzle is extremely straightforward and sql-like. See for yourself:

<Section>
```typescript copy 
await db.insert(users).values({ name: 'Andrew' });
```

```sql
insert into "users" ("id", "name", "age") values (default, 'Andrew', default)
```
</Section>

If you need insert type for a particular table you can use `typeof usersTable.$inferInsert` syntax. 
```typescript copy 
type NewUser = typeof users.$inferInsert;

const insertUser = async (user: NewUser) => {
  return db.insert(users).values(user);
}

const newUser: NewUser = { name: "Alef" };
await insertUser(newUser);
```

## returning

You can insert a row and get it back in CockroachDB like such:
```typescript copy
await db.insert(users).values({ name: "Dan" }).returning();

// partial return
await db.insert(users).values({ name: "Partial Dan" }).returning({ insertedId: users.id });
```

## Insert multiple rows
```typescript copy
await db.insert(users).values([{ name: 'Andrew' }, { name: 'Dan' }]);
```

## Upserts and conflicts
Drizzle ORM provides simple interfaces for handling upserts and conflicts.

### On conflict do nothing

`onConflictDoNothing` will cancel the insert if there's a conflict:

```typescript copy
await db.insert(users)
  .values({ id: 1, name: 'John' })
  .onConflictDoNothing();

// explicitly specify conflict target
await db.insert(users)
  .values({ id: 1, name: 'John' })
  .onConflictDoNothing({ target: users.id });
```

### On conflict do update

`onConflictDoUpdate` will update the row if there's a conflict:
```typescript
await db.insert(users)
  .values({ id: 1, name: 'Dan' })
  .onConflictDoUpdate({ target: users.id, set: { name: 'John' } });
```

#### `where` clauses

`on conflict do update` can have a `where` clause in two different places -
as part of the conflict target (i.e. for partial indexes) or as part of the `update` clause:

```sql
insert into "employees" ("employee_id", "name") 
values (123, 'John Doe') 
on conflict ("employee_id") where name <> 'John Doe' 
do update set "name" = excluded.name;

insert into "employees" ("employee_id", "name") 
values (123, 'John Doe') 
on conflict ("employee_id") do update set "name" = 'John Doe' 
where name <> 'John Doe';
```

To specify these conditions in Drizzle, you can use `setWhere` and `targetWhere` clauses:

```typescript
await db.insert(employees)
  .values({ employeeId: 123, name: 'John Doe' })
  .onConflictDoUpdate({
    target: employees.employeeId,
    targetWhere: sql`name <> 'John Doe'`,
    set: { name: sql`excluded.name` }
  });

await db.insert(employees)
  .values({ employeeId: 123, name: 'John Doe' })
  .onConflictDoUpdate({
    target: employees.employeeId,
    set: { name: 'John Doe' },
    setWhere: sql`name <> 'John Doe'`
  });
```

Upsert with composite indexes, or composite primary keys for `onConflictDoUpdate`:

```typescript
await db.insert(users)
  .values({ firstName: 'John', lastName: 'Doe' })
  .onConflictDoUpdate({
    target: [users.firstName, users.lastName],
    set: { firstName: 'John1' }
  });
```

## `with insert` clause

<Callout>
  Check how to use WITH statement with [select](/docs/cockroach/select#with-clause), [update](/docs/cockroach/update#with-update-clause), [delete](/docs/cockroach/delete#with-delete-clause)
</Callout>

Using the `with` clause can help you simplify complex queries by splitting them into smaller subqueries called common table expressions (CTEs):
<Section>
```typescript copy
const userCount = db.$with('user_count').as(
	db.select({ value: sql`count(*)`.as('value') }).from(users)
);

const result = await db.with(userCount)
	.insert(users)
	.values([
		{ username: 'user1', admin: sql`((select * from ${userCount}) = 0)` }
	])
	.returning({
		admin: users.admin
	});
```
```sql
with "user_count" as (select count(*) as "value" from "users") 
insert into "users" ("username", "admin") 
values ('user1', ((select * from "user_count") = 0)) 
returning "admin"
```
</Section>

## Insert into ... select

As the CockroachDB documentation mentions:
<Callout>
A query (SELECT statement) that supplies the rows to be inserted
</Callout>

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

<Tabs items={["Query Builder", "Callback", "SQL template tag"]}>
<Tab>
<Section>
```ts
const insertedEmployees = await db
  .insert(employees)
  .select(
    db.select({ id: users.id, name: users.name }).from(users).where(eq(users.role, 'employee'))
  )
  .returning({
    id: employees.id,
    name: employees.name
  });
```
```ts
const qb = new QueryBuilder();
await db.insert(employees).select(
    qb.select({ id: users.id, name: users.name }).from(users).where(eq(users.role, 'employee'))
);
```
</Section>
</Tab>
<Tab>
<Section>
```ts
await db.insert(employees).select(
    () => db.select({ id: users.id, name: users.name }).from(users).where(eq(users.role, 'employee'))
);
```
```ts
await db.insert(employees).select(
    (qb) => qb.select({ id: users.id, name: users.name }).from(users).where(eq(users.role, 'employee'))
);
```
</Section>
</Tab>
<Tab>
<Section>
```ts
await db.insert(employees).select(
    sql`select "users"."id" as "id", "users"."name" as "name" from "users" where "users"."role" = 'employee'`
);
```
```ts
await db.insert(employees).select(
    () => sql`select "users"."id" as "id", "users"."name" as "name" from "users" where "users"."role" = 'employee'`
);
```
</Section>
</Tab>
</Tabs>


Source: https://orm.drizzle.team/docs/cockroach/joins

import CodeTabs from '@mdx/CodeTabs.astro';
import CodeTab from '@mdx/CodeTab.astro';
import Section from '@mdx/Section.astro';

# Joins [SQL]
Join clause in SQL is used to combine 2 or more tables, based on related columns between them.
Drizzle ORM joins syntax is a balance between the SQL-likeness and type safety.

## Join types
Drizzle ORM has APIs for `INNER JOIN [LATERAL]`, `FULL JOIN`, `LEFT JOIN [LATERAL]`, `RIGHT JOIN`, `CROSS JOIN [LATERAL]`.
Lets have a quick look at examples based on below table schemas:
```typescript copy
export const users = cockroachTable("users", {
  id: int4().primaryKey(),
  name: string().notNull(),
  age: int4(),
});

export const pets = cockroachTable("pets", {
  id: int4().primaryKey(),
  name: string().notNull(),
  ownerId: int4("owner_id")
    .notNull()
    .references(() => users.id),
});
```

### Left Join
<Section>
```typescript copy
const result = await db.select().from(users).leftJoin(pets, eq(users.id, pets.ownerId))
```
```sql
select ... from "users" left join "pets" on "users"."id" = "pets"."owner_id"
```
```typescript
// result type
const result: {
    users: {
        id: number;
        name: string;
        age: number | null;
    };
    pets: {
        id: number;
        name: string;
        ownerId: number;
    } | null;
}[];
```
</Section>

### Left Join Lateral
<Section>
```typescript copy
const subquery = db.select().from(pets).where(gte(users.age, 16)).as('userPets')
const result = await db.select().from(users).leftJoinLateral(subquery, sql`true`)
```
```sql
select ... from "users" left join lateral (select ... from "pets" where "users"."age" >= 16) "userPets" on true
```
```typescript
// result type
const result: {
    users: {
        id: number;
        name: string;
        age: number | null;
    };
    userPets: {
        id: number;
        name: string;
        ownerId: number;
    } | null;
}[];
```
</Section>

### Right Join
<Section>
```typescript copy
const result = await db.select().from(users).rightJoin(pets, eq(users.id, pets.ownerId))
```
```sql
select ... from "users" right join "pets" on "users"."id" = "pets"."owner_id"
```
```typescript
// result type
const result: {
    users: {
        id: number;
        name: string;
        age: number | null;
    } | null;
    pets: {
        id: number;
        name: string;
        ownerId: number;
    };
}[];
```
</Section>

### Inner Join
<Section>
```typescript copy
const result = await db.select().from(users).innerJoin(pets, eq(users.id, pets.ownerId))
```
```sql
select ... from "users" inner join "pets" on "users"."id" = "pets"."owner_id"
```
```typescript
// result type
const result: {
    users: {
        id: number;
        name: string;
        age: number | null;
    };
    pets: {
        id: number;
        name: string;
        ownerId: number;
    };
}[];
```
</Section>

### Inner Join Lateral
<Section>
```typescript copy
const subquery = db.select().from(pets).where(gte(users.age, 16)).as('userPets')
const result = await db.select().from(users).innerJoinLateral(subquery, sql`true`)
```
```sql
select ... from "users" inner join lateral (select ... from "pets" where "users"."age" >= 16) "userPets" on true
```
```typescript
// result type
const result: {
    users: {
        id: number;
        name: string;
        age: number | null;
    };
    userPets: {
        id: number;
        name: string;
        ownerId: number;
    };
}[];
```
</Section>

### Full Join
<Section>
```typescript copy
const result = await db.select().from(users).fullJoin(pets, eq(users.id, pets.ownerId))
```
```sql
select ... from "users" full join "pets" on "users"."id" = "pets"."owner_id"
```
```typescript
// result type
const result: {
    users: {
        id: number;
        name: string;
        age: number | null;
    } | null;
    pets: {
        id: number;
        name: string;
        ownerId: number;
    } | null;
}[];
```
</Section>

### Cross Join
<Section>
```typescript copy
const result = await db.select().from(users).crossJoin(pets)
```
```sql
select ... from "users" cross join "pets"
```
```typescript
// result type
const result: {
    users: {
        id: number;
        name: string;
        age: number | null;
    };
    pets: {
        id: number;
        name: string;
        ownerId: number;
    };
}[];
```
</Section>

### Cross Join Lateral
<Section>
```typescript copy
const subquery = db.select().from(pets).where(gte(users.age, 16)).as('userPets')
const result = await db.select().from(users).crossJoinLateral(subquery)
```
```sql
select ... from "users" cross join lateral (select ... from "pets" where "users"."age" >= 16) "userPets"
```
```typescript
// result type
const result: {
    users: {
        id: number;
        name: string;
        age: number | null;
    };
    userPets: {
        id: number;
        name: string;
        ownerId: number;
    };
}[];
```
</Section>

## Partial select
If you need to select a particular subset of fields or to have a flat response type, Drizzle ORM
supports joins with partial select and will automatically infer return type based on `.select({ ... })` structure.
<Section>
```typescript copy
await db.select({
  userId: users.id,
  petId: pets.id,
}).from(users).leftJoin(pets, eq(users.id, pets.ownerId))
```
```sql
select "users"."id", "pets"."id" from "users" left join "pets" on "users"."id" = "pets"."owner_id"
```
```typescript
// result type
const result: {
  userId: number;
  petId: number | null;
}[];
```
</Section>
You might've noticed that `petId` can be null now, it's because we're left joining and there can be users without a pet.

It's very important to keep in mind when using `sql` operator for partial selection fields and aggregations when needed,
you should to use `sql<type | null>` for proper result type inference, that one is on you!
<Section>
```typescript copy
const result = await db.select({
  userId: users.id,
  petId: pets.id,
  petName1: sql`upper(${pets.name})`,
  petName2: sql<string | null>`upper(${pets.name})`,
  //˄we should explicitly tell 'string | null' in type, since we're left joining that field
}).from(users).leftJoin(pets, eq(users.id, pets.ownerId))
```
```sql
select "users"."id", "pets"."id", upper("pets"."name")...
from "users" 
left join "pets" on "users"."id" = "pets"."owner_id"
```
```typescript
// result type
const result: {
  userId: number;
  petId: number | null;
  petName1: unknown;
  petName2: string | null;
}[];
```
</Section>
To avoid plethora of nullable fields when joining tables with lots of columns we can utilise our **nested select object syntax**,
our smart type inference will make whole object nullable instead of making all table fields nullable!
<Section>
```typescript copy
await db.select({
  userId: users.id,
  userName: users.name,
  pet: {
    id: pets.id,
    name: pets.name,
    upperName: sql<string>`upper(${pets.name})`
  }
}).from(users).fullJoin(pets, eq(users.id, pets.ownerId))
```
```sql
select ... from "users" full join "pets" on "users"."id" = "pets"."owner_id"
```
```typescript
// result type
const result: {
    userId: number | null;
    userName: string | null;
    pet: {
        id: number;
        name: string;
        upperName: string;
    } | null;
}[];
```
</Section>

## Aliases & Selfjoins
Drizzle ORM supports table aliases which comes really handy when you need to do selfjoins.

Lets say you need to fetch users with their parents:
<CodeTabs items={["index.ts", "schema.ts"]}>
<CodeTab>
```typescript copy
import { user } from "./schema";
import { alias } from "drizzle-orm/cockroach-core";

const parent = alias(user, "parent");
const result = await db
  .select()
  .from(user)
  .leftJoin(parent, eq(parent.id, user.parentId));
```
```sql
select ... from "user" left join "user" "parent" on "parent"."id" = "user"."parent_id"
```
```typescript
// result type
const result: {
    user: {
        id: number;
        name: string;
        parentId: number;
    };
    parent: {
        id: number;
        name: string;
        parentId: number;
    } | null;
}[];
```
</CodeTab>

```typescript
export const user = cockroachTable("user", {
  id: int4().primaryKey(),
  name: string().notNull(),
  parentId: int4("parent_id").notNull().references((): AnyCockroachColumn => user.id)
});
```

</CodeTabs>

## Aggregating results
Drizzle ORM delivers name-mapped results from the driver without changing the structure.

You're free to operate with results the way you want, here's an example of mapping many-one relational data:
```typescript
type User = typeof users.$inferSelect;
type Pet = typeof pets.$inferSelect;

const rows = await db
  .select({
    user: users,
    pet: pets,
  })
  .from(users)
  .leftJoin(pets, eq(users.id, pets.ownerId));

const result = rows.reduce<Record<number, { user: User; pets: Pet[] }>>(
  (acc, row) => {
    const user = row.user;
    const pet = row.pet;

    if (typeof acc[user.id] === "undefined") {
      acc[user.id] = { user, pets: [] };
    }	

    if (pet) {
      acc[user.id]!.pets.push(pet);
    }

    return acc;
  },
  {}
);

// result type
const result: Record<number, {
    user: User;
    pets: Pet[];
}>;
```

## Many-to-one example
```typescript
import { cockroachTable, string, int4 } from "drizzle-orm/cockroach-core";
import { drizzle } from "drizzle-orm/cockroach";

const cities = cockroachTable("cities", {
  id: int4().primaryKey(),
  name: string(),
});

const users = cockroachTable("users", {
  id: int4().primaryKey(),
  name: string(),
  cityId: int4("city_id").references(() => cities.id),
});

const db = drizzle(process.env.DATABASE_URL);

const result = await db.select().from(cities).leftJoin(users, eq(cities.id, users.cityId));
```
## Many-to-many example
```typescript
const users = cockroachTable("users", {
  id: int4().primaryKey(),
  name: string(),
});

const chatGroups = cockroachTable("chat_groups", {
  id: int4().primaryKey(),
  name: string(),
});

const usersToChatGroups = cockroachTable("users_to_chat_groups", {
  userId: int4("user_id")
    .notNull()
    .references(() => users.id),
  groupId: int4("group_id")
    .notNull()
    .references(() => chatGroups.id),
});

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


Source: https://orm.drizzle.team/docs/cockroach/kit-custom-migrations

import CodeTab from '@mdx/CodeTab.astro';
import CodeTabs from '@mdx/CodeTabs.astro';
import Section from '@mdx/Section.astro';
import Tab from '@mdx/Tab.astro';
import Tabs from '@mdx/Tabs.astro';
import Callout from '@mdx/Callout.astro';
import Npm from '@mdx/Npm.astro';
import Npx from '@mdx/Npx.astro';
import Steps from '@mdx/Steps.astro';
import Prerequisites from "@mdx/Prerequisites.astro"

# Migrations with Drizzle Kit
<Prerequisites>
- Get started with Drizzle and `drizzle-kit` - [read here](/docs/cockroach/get-started)
- Drizzle schema fundamentals - [read here](/docs/cockroach/sql-schema-declaration)
- Database connection basics - [read here](/docs/cockroach/connect-overview)
- Drizzle migrations fundamentals - [read here](/docs/cockroach/migrations)
- Drizzle Kit [overview](/docs/cockroach/kit-overview) and [config file](/docs/cockroach/drizzle-config-file)
- `drizzle-kit generate` command - [read here](/docs/cockroach/drizzle-kit-generate)
- `drizzle-kit migrate` command - [read here](/docs/cockroach/drizzle-kit-migrate)
</Prerequisites>

Drizzle lets you generate empty migration files to write your own custom SQL migrations 
for DDL alternations currently not supported by Drizzle Kit or data seeding, which you can then run with [`drizzle-kit migrate`](/docs/cockroach/drizzle-kit-migrate) command.

```shell
drizzle-kit generate --custom --name=seed-users
```
<Section>
```plaintext {4}
📦 <project root>
 ├ 📂 drizzle
 │ ├ 📂 20242409125510_init_sql
 │ └ 📂 20242409135510_seed-users
 ├ 📂 src
 └ …
```
```sql
-- ./drizzle/20242409135510_seed-users.sql

INSERT INTO "users" ("name") VALUES('Dan');
INSERT INTO "users" ("name") VALUES('Andrew');
INSERT INTO "users" ("name") VALUES('Dandrew');
```
</Section>

### Running JavaScript and TypeScript migrations
We will add ability to run custom JavaScript and TypeScript migration/seeding scripts in the upcoming release, you can follow [github discussion](https://github.com/drizzle-team/drizzle-orm/discussions/2832).

Source: https://orm.drizzle.team/docs/cockroach/kit-overview

import CodeTab from '@mdx/CodeTab.astro';
import CodeTabs from '@mdx/CodeTabs.astro';
import Section from '@mdx/Section.astro';
import Tab from '@mdx/Tab.astro';
import Tabs from '@mdx/Tabs.astro';
import Callout from '@mdx/Callout.astro';
import Npm from '@mdx/Npm.astro';
import Npx from '@mdx/Npx.astro';
import Steps from '@mdx/Steps.astro';
import Prerequisites from "@mdx/Prerequisites.astro"

# Migrations with Drizzle Kit
<Prerequisites>
- Get started with Drizzle and `drizzle-kit` - [read here](/docs/cockroach/get-started)
- Drizzle schema fundamentals - [read here](/docs/cockroach/sql-schema-declaration)
- Database connection basics - [read here](/docs/cockroach/connect-overview)
- Drizzle migrations fundamentals - [read here](/docs/cockroach/migrations)
</Prerequisites>


**Drizzle Kit** is a CLI tool for managing SQL database migrations with Drizzle.
<Npm>
  -D drizzle-kit
</Npm>
<Callout type="warning">
Make sure to first go through Drizzle [get started](/docs/cockroach/get-started) and [migration fundamentals](/docs/cockroach/migrations) and pick SQL migration flow that suits your business needs best. 
</Callout>

Based on your schema, Drizzle Kit let's you generate and run SQL migration files, 
push schema directly to the database, pull schema from database, spin up drizzle studio and has a couple of utility commands.
<Npx>
drizzle-kit generate
drizzle-kit migrate
drizzle-kit push
drizzle-kit pull
drizzle-kit check
drizzle-kit up
drizzle-kit studio
drizzle-kit export
</Npx>


|                                                      |                                                                                                                                                                    |
| :--------------------------------------------------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| [`drizzle-kit generate`](/docs/cockroach/drizzle-kit-generate) | lets you generate SQL migration files based on your Drizzle schema either upon declaration or on subsequent changes, [see here](/docs/cockroach/drizzle-kit-generate).       |
| [`drizzle-kit migrate`](/docs/cockroach/drizzle-kit-migrate)   | lets you apply generated SQL migration files to your database, [see here](/docs/cockroach/drizzle-kit-migrate).                                                              |
| [`drizzle-kit pull`](/docs/cockroach/drizzle-kit-pull)         | lets you pull(introspect) database schema, convert it to Drizzle schema and save it to your codebase, [see here](/docs/cockroach/drizzle-kit-pull)                           |
| [`drizzle-kit push`](/docs/cockroach/drizzle-kit-push)         | lets you push your Drizzle schema to database either upon declaration or on subsequent schema changes, [see here](/docs/cockroach/drizzle-kit-push)                          |
| [`drizzle-kit studio`](/docs/cockroach/drizzle-kit-studio)     | will connect to your database and spin up proxy server for Drizzle Studio which you can use for convenient database browsing, [see here](/docs/cockroach/drizzle-kit-studio) |
| [`drizzle-kit check`](/docs/cockroach/drizzle-kit-check)       | will walk through all generate migrations and check for any race conditions(collisions) of generated migrations, [see here](/docs/cockroach/drizzle-kit-check)               |
| [`drizzle-kit up`](/docs/cockroach/drizzle-kit-up)             | used to upgrade snapshots of previously generated migrations, [see here](/docs/cockroach/drizzle-kit-up)                                                                     |
| [`drizzle-kit export`](/docs/cockroach/drizzle-kit-export)     | used to convert a TypeScript schema into raw SQL DDL and print it out [see here](/docs/cockroach/drizzle-kit-export)                                                                     |
<br/>

Drizzle Kit is configured through [drizzle.config.ts](/docs/cockroach/drizzle-config-file) configuration file or via CLI params.<br/>
It's required to at least provide SQL `dialect` and `schema` path for Drizzle Kit to know how to generate migrations.
```
📦 <project root>
 ├ 📂 drizzle
 ├ 📂 src
 ├ 📜 .env
 ├ 📜 drizzle.config.ts  <--- Drizzle config file
 ├ 📜 package.json
 └ 📜 tsconfig.json
```

<CodeTabs items={["simple config", "extended config"]}>
```ts
import { defineConfig } from "drizzle-kit";

export default defineConfig({
  dialect: "cockroach",
  schema: "./src/schema.ts",
});
```
```ts
import { defineConfig } from "drizzle-kit";

export default defineConfig({
  out: "./drizzle",
  dialect: "cockroach",
  schema: "./src/schema.ts",

  entities: {
    roles: {
      exclude: ["admin"],
      include: ["user"],
      provider: "supabase",
    },
  },

  dbCredentials: {
    url: "./database/",
  },

  schemaFilter: "public",
  tablesFilter: "*",

  introspect: {
    casing: "camel",
  },

  migrations: {
    table: "__drizzle_migrations__",
    schema: "public",
  },

  breakpoints: true,
  verbose: true,
});
```
</CodeTabs>

You can provide Drizzle Kit config path via CLI param, it's very useful when you have multiple database stages or multiple databases or different databases on the same project:

<Npx>
  drizzle-kit push --config=drizzle-dev.drizzle.config
  drizzle-kit push --config=drizzle-prod.drizzle.config
</Npx>
```plaintext {5-6}
📦 <project root>
 ├ 📂 drizzle
 ├ 📂 src
 ├ 📜 .env
 ├ 📜 drizzle-dev.config.ts
 ├ 📜 drizzle-prod.config.ts
 ├ 📜 package.json
 └ 📜 tsconfig.json
```


Source: https://orm.drizzle.team/docs/cockroach/migrations

import Callout from '@mdx/Callout.astro';
import Steps from '@mdx/Steps.astro';
import CodeTab from '@mdx/CodeTab.astro';
import CodeTabs from '@mdx/CodeTabs.astro';
import Section from '@mdx/Section.astro';
import Tab from '@mdx/Tab.astro';
import Tabs from '@mdx/Tabs.astro';
import Npm from '@mdx/Npm.astro';
import Tag from '@mdx/Tag.astro'


# Drizzle migrations fundamentals

SQL databases require you to specify a **strict schema** of entities you're going to store upfront 
and if (when) you need to change the shape of those entities - you will need to do it via **schema migrations**.

There're multiple production grade ways of managing database migrations. 
Drizzle is designed to perfectly suits all of them, regardless of you going **database first** or **codebase first**.

**Database first** is when your database schema is a source of truth. You manage your database schema either directly on the database or 
via database migration tools and then you pull your database schema to your codebase application level entities.  
 
**Codebase first** is when database schema in your codebase is a source of truth and is under version control. You declare and manage your database schema in JavaScript/TypeScript
and then you apply that schema to the database itself either with Drizzle, directly or via external migration tools. 

#### How can Drizzle help?
We've built [**drizzle-kit**](/docs/cockroach/kit-overview) - CLI app for managing migrations with Drizzle. 
```shell
drizzle-kit migrate
drizzle-kit generate
drizzle-kit push
drizzle-kit pull
drizzle-kit export
```
It is designed to let you choose how to approach migrations based on your current business demands. 

It fits in both database and codebase first approaches, it lets you **push your schema** or **generate SQL migration** files or **pull the schema** from database. 
It is perfect wether you work alone or in a team.
<br/>

<hr/>
<rem/>

**Now let's pick the best option for your project:**
<rem/>

<Tag style="font-size: 12px">**Option 1**</Tag>
> I manage database schema myself using external migration tools or by running SQL migrations directly on my database.
> From Drizzle I just need to get current state of the schema from my database and save it as TypeScript schema file.

<Callout collapsed="Expand details">
That's a **database first** approach. You have your database schema as a **source of truth** and 
Drizzle lets you pull database schema to TypeScript using [`drizzle-kit pull`](/docs/cockroach/drizzle-kit-pull) command.

<Section>
```
                                  ┌────────────────────────┐      ┌─────────────────────────┐ 
                                  │                        │ <---  CREATE TABLE "users" (
┌──────────────────────────┐      │                        │        "id" INT4 PRIMARY KEY,
│ ~ drizzle-kit pull       │      │                        │        "name" STRING,
└─┬────────────────────────┘      │        DATABASE        │        "email" STRING UNIQUE
  │                               │                        │       );
  └ Pull datatabase schema -----> │                        │
  ┌ Generate Drizzle       <----- │                        │
  │ schema TypeScript file        └────────────────────────┘
  │
  v
```
```typescript
import * as p from "drizzle-orm/cockroach-core";

export const users = p.cockroachTable("users", {
	id: p.int4().primaryKey(),
	name: p.string(),
	email: p.string(),
}, (table) => [
	uniqueIndex("users_email_key").using("btree", table.email.asc()),
]);
```
</Section>
</Callout>

<rem/>
<rem/>
<rem/>

<Tag style="font-size: 12px">**Option 2**</Tag>
> I want to have database schema in my TypeScript codebase, 
> I don't wanna deal with SQL migration files.  
> I want Drizzle to "push" my schema directly to the database

<Callout collapsed="Expand details">
That's a **codebase first** approach. You have your TypeScript Drizzle schema as a **source of truth** and 
Drizzle lets you push schema changes to the database using [`drizzle-kit push`](/docs/cockroach/drizzle-kit-push) command.

That's the best approach for rapid prototyping and we've seen dozens of teams 
and solo developers successfully using it as a primary migrations flow in their production applications.

<Section>
```typescript {6} filename="src/schema.ts"
import * as p from "drizzle-orm/cockroach-core";

export const users = p.cockroachTable("users", {
  id: p.int4().primaryKey(),
  name: p.string(),
  email: p.string().unique(), // <--- added column
});
```
```
Add column to `users` table                                                                          
┌────────────────────────────┐                  
│ + email: string().unique() │                  
└─┬──────────────────────────┘                  
  │                                           
  v                                           
┌──────────────────────────┐                  
│ ~ drizzle-kit push       │                  
└─┬────────────────────────┘                  
  │                                           ┌──────────────────────────┐
  └ Pull current datatabase schema ---------> │                          │
                                              │                          │
  ┌ Generate alternations based on diff <---- │         DATABASE         │
  │                                           │                          │
  └ Apply migrations to the database -------> │                          │
                                       │      └──────────────────────────┘
                                       │
  ┌────────────────────────────────────┴──────────────────────┐
   ALTER TABLE "users" ADD COLUMN "email" string;
   CREATE UNIQUE INDEX "users_email_key" ON "users" ("email");
```
</Section>
</Callout>

<rem/>
<rem/>
<rem/>

<Tag style="font-size: 12px">**Option 3**</Tag>
> I want to have database schema in my TypeScript codebase, 
> I want Drizzle to generate SQL migration files for me and apply them to my database

<Callout collapsed="Expand details">
That's a **codebase first** approach. You have your TypeScript Drizzle schema as a source of truth and 
Drizzle lets you generate SQL migration files based on your schema changes with [`drizzle-kit generate`](/docs/cockroach/drizzle-kit-generate)
and then apply them to the database with [`drizzle-kit migrate`](/docs/cockroach/drizzle-kit-migrate) commands. 
<Section>
```typescript filename="src/schema.ts"
import * as p from "drizzle-orm/cockroach-core";

export const users = p.cockroachTable("users", {
  id: p.int4().primaryKey(),
  name: p.string(),
  email: p.string().unique(),
});
```
```                                  
┌────────────────────────┐                  
│ $ drizzle-kit generate │                  
└─┬──────────────────────┘                  
  │                                           
  └ 1. read previous migration folders
    2. find diff between current and previous schema
    3. prompt developer for renames if necessary
  ┌ 4. generate SQL migration and persist to file
  │    ┌─┴───────────────────────────────────────┐  
  │      📂 drizzle       
  │      └ 📂 20242409125510_premium_mister_fear
  │        ├ 📜 snapshot.json
  │        └ 📜 migration.sql
  v
```
```sql
-- drizzle/20242409125510_premium_mister_fear/migration.sql

CREATE TABLE "users" (
	"id" int4 PRIMARY KEY,
	"name" string,
	"email" string,
	CONSTRAINT "users_email_key" UNIQUE("email")
);
```
```
┌───────────────────────┐                  
│ $ drizzle-kit migrate │                  
└─┬─────────────────────┘                  
  │                                                         ┌──────────────────────────┐                                         
  └ 1. read migration.sql files in migrations folder        │                          │
    2. fetch migration history from database -------------> │                          │
  ┌ 3. pick previously unapplied migrations <-------------- │         DATABASE         │
  └ 4. apply new migration to the database ---------------> │                          │
                                                            │                          │
                                                            └──────────────────────────┘
[✓] done!                                                 
```
</Section>
</Callout>

<rem/>
<rem/>
<rem/>

<Tag style="font-size: 12px">**Option 4**</Tag>
> I want to have database schema in my TypeScript codebase,
> I want Drizzle to generate SQL migration files for me and I want Drizzle to apply them during runtime

<Callout collapsed="Expand details">
That's a **codebase first** approach. You have your TypeScript Drizzle schema as a source of truth and 
Drizzle lets you generate SQL migration files based on your schema changes with [`drizzle-kit generate`](/docs/cockroach/drizzle-kit-generate) and then 
you can apply them to the database during runtime of your application.

This approach is widely used for **monolithic** applications when you apply database migrations 
during zero downtime deployment and rollback DDL changes if something fails. 
This is also used in **serverless** deployments with migrations running in **custom resource** once during deployment process.

<Section>
```typescript filename="src/schema.ts"
import * as p from "drizzle-orm/cockroach-core";

export const users = p.cockroachTable("users", {
  id: p.int4().primaryKey(),
  name: p.string(),
  email: p.string().unique(),
});
```
```                                  
┌────────────────────────┐                  
│ $ drizzle-kit generate │                  
└─┬──────────────────────┘                  
  │                                           
  └ 1. read previous migration folders
    2. find diff between current and previous schema
    3. prompt developer for renames if necessary
  ┌ 4. generate SQL migration and persist to file
  │    ┌─┴───────────────────────────────────────┐  
  │      📂 drizzle       
  │      └ 📂 20242409125510_premium_mister_fear
  │        ├ 📜 snapshot.json
  │        └ 📜 migration.sql
  v
```
```sql
-- drizzle/20242409125510_premium_mister_fear/migration.sql

CREATE TABLE "users" (
	"id" int4 PRIMARY KEY,
	"name" string,
	"email" string,
	CONSTRAINT "users_email_key" UNIQUE("email")
);
```
```ts
// index.ts
import { drizzle } from "drizzle-orm/cockroach"
import { migrate } from 'drizzle-orm/cockroach/migrator';

const db = drizzle(process.env.DATABASE_URL);

await migrate(db);
```
```
┌───────────────────────┐                  
│ npx tsx src/index.ts  │                  
└─┬─────────────────────┘                  
  │                                                      
  ├ 1. init database connection                             ┌──────────────────────────┐                                         
  └ 2. read migration.sql files in migrations folder        │                          │
    3. fetch migration history from database -------------> │                          │
  ┌ 4. pick previously unapplied migrations <-------------- │         DATABASE         │
  └ 5. apply new migration to the database ---------------> │                          │
                                                            │                          │
                                                            └──────────────────────────┘
[✓] done!                                                 
```
</Section>
</Callout>

<rem/>
<rem/>
<rem/>

<Tag style="font-size: 12px">**Option 5**</Tag>
> I want to have database schema in my TypeScript codebase,
> I want Drizzle to generate SQL migration files for me,
> but I will apply them to my database myself or via external migration tools 

<Callout collapsed="Expand details">
That's a **codebase first** approach. You have your TypeScript Drizzle schema as a source of truth and 
Drizzle lets you generate SQL migration files based on your schema changes with [`drizzle-kit generate`](/docs/cockroach/drizzle-kit-generate) and then 
you can apply them to the database either directly or via external migration tools.

<Section>
```typescript filename="src/schema.ts"
import * as p from "drizzle-orm/cockroach-core";

export const users = p.cockroachTable("users", {
  id: p.int4().primaryKey(),
  name: p.string(),
  email: p.string().unique(),
});
```
```                                  
┌────────────────────────┐                  
│ $ drizzle-kit generate │                  
└─┬──────────────────────┘                  
  │                                           
  └ 1. read previous migration folders
    2. find diff between current and previous scheama
    3. prompt developer for renames if necessary
  ┌ 4. generate SQL migration and persist to file
  │    ┌─┴───────────────────────────────────────┐  
  │      📂 drizzle       
  │      └ 📂 20242409125510_premium_mister_fear
  │        ├ 📜 snapshot.json
  │        └ 📜 migration.sql
  v
```
```sql
-- drizzle/20242409125510_premium_mister_fear/migration.sql

CREATE TABLE "users" (
	"id" int4 PRIMARY KEY,
	"name" string,
	"email" string,
	CONSTRAINT "users_email_key" UNIQUE("email")
);
```
```
┌───────────────────────────────────┐                  
│ (._.) now you run your migrations │           
└─┬─────────────────────────────────┘  
  │
 directly to the database
  │                                         ┌────────────────────┐
  ├────────────────────────────────────┬───>│                    │  
  │                                    │    │      Database      │           
 or via external tools                 │    │                    │   
  │                                    │    └────────────────────┘
  │  ┌────────────────────┐            │      
  └──│ Bytebase           ├────────────┘         
     ├────────────────────┤  
     │ Liquibase          │
     ├────────────────────┤ 
     │ Atlas              │
     ├────────────────────┤ 
     │ etc…               │
     └────────────────────┘

[✓] done!                                                 
```
</Section>
</Callout>

<rem/>
<rem/>
<rem/>

<Tag style="font-size: 12px">**Option 6**</Tag>
> I want to have database schema in my TypeScript codebase,
> I want Drizzle to output the SQL representation of my Drizzle schema to the console,
> and I will apply them to my database via [Atlas](https://atlasgo.io/guides/orms/drizzle)

<Callout collapsed="Expand details">
That's a **codebase first** approach. You have your TypeScript Drizzle schema as a source of truth and 
Drizzle lets you export SQL statements based on your schema changes with [`drizzle-kit export`](/docs/cockroach/drizzle-kit-generate) and then 
you can apply them to the database via [Atlas](https://atlasgo.io/guides/orms/drizzle) or other external SQL migration tools.

<Section>
```typescript filename="src/schema.ts"
import * as p from "drizzle-orm/cockroach-core";

export const users = p.cockroachTable("users", {
  id: p.int4().primaryKey(),
  name: p.string(),
  email: p.string().unique(),
});
```
```                                  
┌────────────────────────┐                  
│ $ drizzle-kit export   │                  
└─┬──────────────────────┘                  
  │                                           
  └ 1. read your drizzle schema
    2. generated SQL representation of your schema
  ┌ 3. outputs to console
  │    
  │        
  v
```
```sql
CREATE TABLE "users" (
	"id" int4 PRIMARY KEY,
	"name" string,
	"email" string,
	CONSTRAINT "users_email_key" UNIQUE("email")
);
```
```
┌───────────────────────────────────┐                  
│ (._.) now you run your migrations │           
└─┬─────────────────────────────────┘  
  │
 via Atlas
  │                                    ┌──────────────┐
  │  ┌────────────────────┐            │              │
  └──│ Atlas              ├───────────>│  Database    │      
     └────────────────────┘            │              │       
                                       └──────────────┘

[✓] done!                                                 
```
</Section>
</Callout>

<rem/>
<rem/>


Source: https://orm.drizzle.team/docs/cockroach/operators

import Section from '@mdx/Section.astro';
import Callout from "@mdx/Callout.astro";

# Filter and conditional operators

<Callout type='info'>
All the values provided to filter operators and to the `sql` function are parameterized automatically.
For example, this query:
```ts
await db.select().from(users).where(eq(users.id, 42));
```
will be translated to:
```sql
select "id", "name", "age" from "users" where "users"."id" = $1; -- params: [42]
```
</Callout>

<br/>

We natively support all dialect specific filter and conditional operators.

You can import all filter & conditional from `drizzle-orm`:
```typescript copy
import { eq, ne, gt, gte, ... } from "drizzle-orm";
```

### eq

  
Value equal to `n`
<Section>
```typescript copy
import { eq } from "drizzle-orm";

db.select().from(table).where(eq(table.column, 5));
```

```sql copy
SELECT * FROM "table" WHERE "table"."column" = 5
```
</Section>

<Section>
```typescript
import { eq } from "drizzle-orm";

db.select().from(table).where(eq(table.column1, table.column2));
```

```sql
SELECT * FROM "table" WHERE "table"."column1" = "table"."column2"
```
</Section>

### ne

  
Value is not equal to `n`  
<Section>
```typescript
import { ne } from "drizzle-orm";

db.select().from(table).where(ne(table.column, 5));
```

```sql
SELECT * FROM "table" WHERE "table"."column" <> 5
```
</Section>

<Section>
```typescript
import { ne } from "drizzle-orm";

db.select().from(table).where(ne(table.column1, table.column2));
```

```sql
SELECT * FROM "table" WHERE "table"."column1" <> "table"."column2"
```
</Section>

## ---

### gt
 
  
Value is greater than `n`
<Section>
```typescript
import { gt } from "drizzle-orm";

db.select().from(table).where(gt(table.column, 5));
```

```sql
SELECT * FROM "table" WHERE "table"."column" > 5
```
</Section>

<Section>
```typescript
import { gt } from "drizzle-orm";

db.select().from(table).where(gt(table.column1, table.column2));
```

```sql
SELECT * FROM "table" WHERE "table"."column1" > "table"."column2"
```
</Section>

### gte

  
Value is greater than or equal to `n`
<Section>
```typescript
import { gte } from "drizzle-orm";

db.select().from(table).where(gte(table.column, 5));
```

```sql
SELECT * FROM "table" WHERE "table"."column" >= 5
```
</Section>

<Section>
```typescript
import { gte } from "drizzle-orm";

db.select().from(table).where(gte(table.column1, table.column2));
```

```sql
SELECT * FROM "table" WHERE "table"."column1" >= "table"."column2"
```
</Section>

### lt

  
Value is less than `n`
<Section>
```typescript
import { lt } from "drizzle-orm";

db.select().from(table).where(lt(table.column, 5));
```

```sql
SELECT * FROM "table" WHERE "table"."column" < 5
```
</Section>

<Section>
```typescript
import { lt } from "drizzle-orm";

db.select().from(table).where(lt(table.column1, table.column2));
```

```sql
SELECT * FROM "table" WHERE "table"."column1" < "table"."column2"
```
</Section>

### lte

  
Value is less than or equal to `n`.

<Section>
```typescript
import { lte } from "drizzle-orm";

db.select().from(table).where(lte(table.column, 5));
```

```sql
SELECT * FROM "table" WHERE "table"."column" <= 5
```
</Section>

<Section>
```typescript
import { lte } from "drizzle-orm";

db.select().from(table).where(lte(table.column1, table.column2));
```

```sql
SELECT * FROM "table" WHERE "table"."column1" <= "table"."column2"
```
</Section>

## ---

### exists

  
Value exists
<Section>
```typescript
import { exists } from "drizzle-orm";

const query = db.select().from(table2)
db.select().from(table).where(exists(query));
```

```sql
SELECT * FROM "table" WHERE EXISTS (SELECT * FROM "table2")
```
</Section>

### notExists

<Section>
```typescript
import { notExists } from "drizzle-orm";

const query = db.select().from(table2)
db.select().from(table).where(notExists(query));
```

```sql
SELECT * FROM "table" WHERE NOT EXISTS (SELECT * FROM "table2")
```
</Section>

### isNull
  
Value is `null`
<Section>
```typescript
import { isNull } from "drizzle-orm";

db.select().from(table).where(isNull(table.column));
```

```sql
SELECT * FROM "table" WHERE ("table"."column" IS NULL)
```
</Section>

### isNotNull

  
Value is not `null`
<Section>
```typescript
import { isNotNull } from "drizzle-orm";

db.select().from(table).where(isNotNull(table.column));
```

```sql
SELECT * FROM "table" WHERE ("table"."column" IS NOT NULL)
```
</Section>

## ---

### inArray

  
Value is in array of values
<Section>
```typescript
import { inArray } from "drizzle-orm";

db.select().from(table).where(inArray(table.column, [1, 2, 3, 4]));
```

```sql
SELECT * FROM "table" WHERE "table"."column" IN (1, 2, 3, 4)
```
</Section>

<Section>
```typescript
import { inArray } from "drizzle-orm";

const query = db.select({ data: table2.column }).from(table2);
db.select().from(table).where(inArray(table.column, query));
```

```sql
SELECT * FROM "table" WHERE "table"."column" IN (SELECT "table2"."column" FROM "table2")
```
</Section>

### notInArray

  
Value is not in array of values
<Section>
```typescript
import { notInArray } from "drizzle-orm";

db.select().from(table).where(notInArray(table.column, [1, 2, 3, 4]));
```

```sql
SELECT * FROM "table" WHERE "table"."column" NOT IN (1, 2, 3, 4)
```
</Section>

<Section>
```typescript
import { notInArray } from "drizzle-orm";

const query = db.select({ data: table2.column }).from(table2);
db.select().from(table).where(notInArray(table.column, query));
```

```sql
SELECT * FROM "table" WHERE "table"."column" NOT IN (SELECT "table2"."column" FROM "table2")
```
</Section>

## ---

### between

  
Value is between two values
<Section>
```typescript
import { between } from "drizzle-orm";

db.select().from(table).where(between(table.column, 2, 7));
```

```sql
SELECT * FROM "table" WHERE "table"."column" BETWEEN 2 AND 7
```
</Section>

### notBetween

  
Value is not between two value
<Section>
```typescript
import { notBetween } from "drizzle-orm";

db.select().from(table).where(notBetween(table.column, 2, 7));
```

```sql
SELECT * FROM "table" WHERE "table"."column" NOT BETWEEN 2 AND 7
```
</Section>

## ---

### like

  
Value is like other value, case sensitive
<Section>
```typescript
import { like } from "drizzle-orm";

db.select().from(table).where(like(table.column, "%llo wor%"));
```

```sql
SELECT * FROM "table" WHERE "table"."column" LIKE '%llo wor%'
```
</Section>

### notLike

  
Value is not like other value, case sensitive
<Section>
```typescript
import { notLike } from "drizzle-orm";

db.select().from(table).where(notLike(table.column, "%llo wor%"));
```

```sql
SELECT * FROM "table" WHERE "table"."column" NOT LIKE '%llo wor%'
```
</Section>

### ilike

  
Value is like some other value, case insensitive
<Section>
```typescript
import { ilike } from "drizzle-orm";

db.select().from(table).where(ilike(table.column, "%llo wor%"));
```

```sql
SELECT * FROM "table" WHERE "table"."column" ILIKE '%llo wor%'
```
</Section>

### notIlike

  
Value is not like some other value, case insensitive
<Section>
```typescript
import { notIlike } from "drizzle-orm";

db.select().from(table).where(notIlike(table.column, "%llo wor%"));
```

```sql
SELECT * FROM "table" WHERE "table"."column" NOT ILIKE '%llo wor%'
```
</Section>

## ---

### not

  
All conditions must return `false`.

<Section>
```typescript
import { eq, not } from "drizzle-orm";

db.select().from(table).where(not(eq(table.column, 5)));
```

```sql
SELECT * FROM "table" WHERE NOT ("table"."column" = 5)
```
</Section>

### and

  
All conditions must return `true`.

<Section>
```typescript
import { gt, lt, and } from "drizzle-orm";

db.select().from(table).where(and(gt(table.column, 5), lt(table.column, 7)));
```

```sql
SELECT * FROM "table" WHERE ("table"."column" > 5 AND "table"."column" < 7)
```
</Section>

### or

  
One or more conditions must return `true`.

<Section>
```typescript
import { gt, lt, or } from "drizzle-orm";

db.select().from(table).where(or(gt(table.column, 5), lt(table.column, 7)));
```

```sql
SELECT * FROM "table" WHERE ("table"."column" > 5 OR "table"."column" < 7)
```
</Section>

## ---

### arrayContains

  
Test that a column or expression contains all elements of the list passed as the second argument

<Section>
```typescript
import { arrayContains } from "drizzle-orm";

const contains = await db.select({ id: posts.id }).from(posts)
  .where(arrayContains(posts.tags, ['Typescript', 'ORM']));

const withSubQuery = await db.select({ id: posts.id }).from(posts)
  .where(arrayContains(
    posts.tags,
    db.select({ tags: posts.tags }).from(posts).where(eq(posts.id, 1)),
  ));
```

```sql
select "id" from "posts" where "posts"."tags" @> {Typescript,ORM};
select "id" from "posts" where "posts"."tags" @> (select "tags" from "posts" where "posts"."id" = 1);
```
</Section>

### arrayContained

  
Test that the list passed as the second argument contains all elements of a column or expression

<Section>
```typescript
import { arrayContained } from "drizzle-orm";

const contained = await db.select({ id: posts.id }).from(posts)
  .where(arrayContained(posts.tags, ['Typescript', 'ORM']));
```

```sql
select "id" from "posts" where "posts"."tags" <@ {Typescript,ORM};
```
</Section>

### arrayOverlaps

  
Test that a column or expression contains any elements of the list passed as the second argument.

<Section>
```typescript
import { arrayOverlaps } from "drizzle-orm";

const overlaps = await db.select({ id: posts.id }).from(posts)
  .where(arrayOverlaps(posts.tags, ['Typescript', 'ORM']));
```

```sql
select "id" from "posts" where "posts"."tags" && {Typescript,ORM}
```
</Section>


Source: https://orm.drizzle.team/docs/cockroach/overview

import Callout from '@mdx/Callout.astro';
import CodeTabs from '@mdx/CodeTabs.astro';
import YoutubeCards from '@mdx/YoutubeCards.astro';
import GetStartedLinks from '@mdx/GetStartedLinks/index.astro'

# Drizzle ORM

Drizzle ORM is a headless TypeScript ORM with a head. 🐲
> Drizzle is a good friend who's there for you when necessary and doesn't bother when you need some space.

It looks and feels simple, performs on day _1000_ of your project,\
lets you do things your way, and is there when you need it.

**It's the only ORM with both [relational](/docs/cockroach/rqb) and [SQL-like](/docs/cockroach/select) query APIs**, 
providing you the best of both worlds when it comes to accessing your relational data. 
Drizzle is lightweight, performant, typesafe, non-lactose, gluten-free, sober, flexible and **serverless-ready by design**.
Drizzle is not just a library, it's an experience. 🤩

[![Drizzle bestofjs](@/assets/images/bestofjs.jpg)](https://bestofjs.org/projects/drizzle-orm)

## Headless ORM? 
First and foremost, Drizzle is a library and a collection of complementary opt-in tools. 

**ORM** stands for _object relational mapping_, and developers tend to call Django-like or Spring-like tools an ORM. 
We truly believe it's a misconception based on legacy nomenclature, and we call them **data frameworks**.

<Callout type="error" emoji="️💔">
  With data frameworks you have to build projects **around them** and not **with them**.
</Callout>

**Drizzle** lets you build your project the way you want, without interfering with your project or structure. 

Using Drizzle you can define and manage database schemas in TypeScript, access your data in a SQL-like 
or relational way, and take advantage of opt-in tools 
to push your developer experience _through the roof_. 🤯 

## Why SQL-like?
**If you know SQL, you know Drizzle.**

Other ORMs and data frameworks tend to deviate/abstract you away from SQL, which 
leads to a double learning curve: needing to know both SQL and the framework's API.  

Drizzle is the opposite. 
We embrace SQL and built Drizzle to be SQL-like at its core, so you can have zero to no 
learning curve and access to the full power of SQL.  

We bring all the familiar **[SQL schema](/docs/cockroach/sql-schema-declaration)**, **[queries](/docs/cockroach/select)**, 
**[automatic migrations](/docs/cockroach/migrations)** and **[one more thing](/docs/cockroach/rqb)**. ✨

<CodeTabs items={["index.ts", "schema.ts", "migration.sql"]}>
```typescript copy
// Access your data
await db
	.select()
	.from(countries)
	.leftJoin(cities, eq(cities.countryId, countries.id))
	.where(eq(countries.id, 10))
```
```typescript copy
// manage your schema
export const countries = cockroachTable('countries', {
  id: int4().primaryKey(),
  name: varchar({ length: 256 }),
});

export const cities = cockroachTable('cities', {
  id: int4().primaryKey(),
  name: varchar({ length: 256 }),
  countryId: int4('country_id').references(() => countries.id),
});
```
```sql
-- generate migrations
CREATE TABLE "countries" (
	"id" int4 PRIMARY KEY,
	"name" varchar(256)
);

CREATE TABLE "cities" (
	"id" int4 PRIMARY KEY,
	"name" varchar(256),
	"country_id" int4
);

ALTER TABLE "cities" ADD CONSTRAINT "cities_country_id_countries_id_fkey" FOREIGN KEY ("country_id") REFERENCES "countries"("id");
```
</CodeTabs>

## Why not SQL-like?
We're always striving for a perfectly balanced solution, and while SQL-like does cover 100% of the needs, 
there are certain common scenarios where you can query data in a better way.  

We've built the **[Queries API](/docs/cockroach/rqb)** for you, so you can fetch relational nested data from the database 
in the most convenient and performant way, and never think about joins and data mapping.  

**Drizzle always outputs exactly 1 SQL query.** Feel free to use it with serverless databases and never worry about performance or roundtrip costs!

```ts
const result = await db._query.users.findMany({
	with: {
		posts: true
	},
});
```

## Serverless?
<Callout type="info" emoji="🥳">
  The best part is no part. **Drizzle has exactly 0 dependencies!**
</Callout>


![Drizzle is slim an Serverless ready](@/assets/images/drizzle31kb.jpg)
  
Drizzle ORM is dialect-specific, slim, performant and serverless-ready **by design**.  

We've spent a lot of time to make sure you have best-in-class SQL dialect support, including Postgres, MySQL, and others.

Drizzle operates natively through industry-standard database drivers. We support all major **[PostgreSQL](/docs/get-started-postgresql)**, **[MySQL](/docs/mysql/get-started-mysql)**, **[SQLite](/docs/sqlite/get-started-sqlite)**, **[SingleStore](/docs/singlestore/get-started-singlestore)**, **[MSSQL](/docs/mssql/get-started-mssql)** or **[CockroachDB](/docs/cockroach/get-started-cockroach)** drivers out there, and we're adding new ones **[really fast](https://twitter.com/DrizzleORM/status/1653082492742647811?s=20)**.  


## Welcome on board!
More and more companies are adopting Drizzle in production, experiencing immense benefits in both DX and performance.

**We're always there to help, so don't hesitate to reach out. We'll gladly assist you in your Drizzle journey!**

We have an outstanding **[Discord community](https://driz.link/discord)** and welcome all builders to our **[Twitter](https://twitter.com/drizzleorm)**.
  
Now go build something awesome with Drizzle and your **[PostgreSQL](/docs/get-started-postgresql)**, **[MySQL](/docs/mysql/get-started-mysql)**, **[SQLite](/docs/sqlite/get-started-sqlite)**, **[MSSQL](/docs/mssql/get-started-mssql)** or **[CockroachDB](/docs/cockroach/get-started-cockroach)** database. 🚀

### Video Showcase

{/* tRPC + NextJS App Router = Simple Typesafe APIs
Jack Herrington 19:17
https://www.youtube.com/watch?v=qCLV0Iaq9zU */}
{/* https://www.youtube.com/watch?v=qDunJ0wVIec */}
{/* https://www.youtube.com/watch?v=NZpPMlSAez0 */}

 {/* https://www.youtube.com/watch?v=-A0kMiJqQRY */}

<YoutubeCards cards={[
	{
		id: "vyU5mJGCJMw",
		title: "Full Drizzle Course for Beginners",
		description: "Code Genix",
		time: "1:37:39",
	},
	{
		id: "7-NZ0MlPpJA",
		title: "Learn Drizzle In 60 Minutes",
		description: "Web Dev Simplified",
		time: "56:09"
	},
	{
		id: "i_mAHOhpBSA",
		title: "Drizzle ORM in 100 Seconds",
		description: "Fireship",
		time: "2:55"
	},
	{
		id: "hIYNOiZXQ7Y",
		title: "Learn Drizzle ORM in 13 mins (crash course)",
		description: "Neon",
		time: "14:00"
	},
	{
		id: "4ZhtoOFKFP8",
		title: "Easiest Database Setup in Next.js&nbsp;14 with Turso&nbsp;&&nbsp;Drizzle",
		description: "Sam Meech-Ward",
		time: '38:08'
	}, 
	{
		id: "NfVELsEZFsA",
		title: "Next.js Project with Vercel, Neon, Drizzle, TailwindCSS, FlowBite and more!",
		description: "CodingEntrepreneurs",
		time: '5:46:28'
	}, 
	{
		id: "_SLxGYzv6jo",
		title: "I Have A New Favorite Database&nbsp;Tool",
		description: "Theo - t3.gg",
		time: '5:46'
	}, 
	{
		id: "Qo-RXkSwOtc",
		title: "Drizzle ORM First impressions - migrations, relations, queries!",
		description: "Marius Espejo",
		time: '33:52'
	},
	{
		id: "yXNEqyvA0OY",
		title: "I want to learn Drizzle ORM, so I'm starting another next14 project",
		description: "Web Dev Cody",
		time: "9:00"
	},
	{
		id: "h7vVhR-dFYo",
		title: "Picking an ORM is Getting Harder...",
		description: "Ben Davis",
		time: "5:18"
	},
	{
		id: "8met6WTk0mQ",
		title: "This New Database Tool is a Game-Changer",
		description: "Josh tried coding",
		time: "8:49"
	},
	{
		id: "woWW1T9DXEY",
		title: "My Favorite Database Tool Just Got EVEN Better",
		description: "Josh tried coding",
		time: "4:23"
	},
	{
		id: "A3l6YYkXzzg",
		title: "SaaS Notion Clone with Realtime cursors, Nextjs 13, Stripe, Drizzle ORM, Tailwind, Supabase, Sockets",
		description: "Web Prodigies",
		time: "11:41:46"
	},
	{
		id: "EQfaw5bDE1s",
		title: "SvelteKit + Drizzle Code Breakdown",
		description: "Ben Davis",
		time: "12:18"
	},
	{
		id: "b6VhN_HHDiQ",
		title: "Build a Multi-Tenanted, Role-Based Access Control System",
		description: "TomDoesTech",
		time: "2:01:29"
	},
	/*
	This video became private
	Uncomment (in other files too) it when it becomes public again
	{
		id: "3tl9XCiQErA",
		title: "The Prisma killer is finally here",
		description: "SST",
		time: "5:42"
	},
	*/
	{
		id: "VQFjyEa8vGE",
		title: "Learning Drizzle ORM and working on a next14 project",
		description: "Web Dev Cody",
		time: "1:07:41"
	},
	{
		id: "5G0upg4sxgE",
		title: "This Trick Makes My Favorite Database Tool Even Better",
		description: "Josh tried coding",
		time: "6:01"
	},
	{
		id: "-JnEuvPmt-Q",
		title: "Effortless Auth in Next.js 14: Use Auth.js & Drizzle ORM for Secure Login",
		description: "Sam Meech-Ward",
		time: "26:29"
	},
]} />


Source: https://orm.drizzle.team/docs/cockroach/perf-queries

# Query performance
When it comes to **Drizzle** — we're a thin TypeScript layer on top of SQL with 
almost 0 overhead and to make it actual 0, you can utilise our prepared statements API.
  
**When you run a query on the database, there are several things that happen:**
- all the configurations of the query builder got concatenated to the SQL string
- that string and params are sent to the database driver
- driver compiles SQL query to the binary SQL executable format and sends it to the database

With prepared statements you do SQL concatenation once on the Drizzle ORM side and then database 
driver is able to reuse precompiled binary SQL instead of parsing query all the time. 
It has extreme performance benefits on large SQL queries.  

## Prepared statement

	```typescript copy {3}
    const db = drizzle(...);

    const prepared = db.select().from(customers).prepare("statement_name");
    
    const res1 = await prepared.execute();
    const res2 = await prepared.execute();
    const res3 = await prepared.execute();
    ```

## Placeholder
Whenever you need to embed a dynamic runtime value - you can use the `sql.placeholder(...)` api

```ts {6,9-10,15,18}
    import { sql } from "drizzle-orm";

    const p1 = db
      .select()
      .from(customers)
      .where(eq(customers.id, sql.placeholder('id')))
      .prepare("p1")

    await p1.execute({ id: 10 }) // SELECT * FROM customers WHERE id = 10
    await p1.execute({ id: 12 }) // SELECT * FROM customers WHERE id = 12

    const p2 = db
      .select()
      .from(customers)
      .where(sql`lower(${customers.name}) like ${sql.placeholder('name')}`)
      .prepare("p2");

    await p2.execute({ name: '%an%' }) // SELECT * FROM customers WHERE lower(name) like '%an%'
    ```


Source: https://orm.drizzle.team/docs/cockroach/query-utils

import $count from '@mdx/$count-cockroach.mdx';

# Drizzle query utils

### $count
<$count/>

Source: https://orm.drizzle.team/docs/cockroach/read-replicas

# Read Replicas

When your project involves a set of read replica instances, and you require a convenient method for managing 
SELECT queries from read replicas, as well as performing create, delete, and update operations on the primary 
instance, you can leverage the `withReplicas()` function within Drizzle

```ts copy
import { sql } from 'drizzle-orm';
import { drizzle } from 'drizzle-orm/cockroach';
import { boolean, jsonb, cockroachTable, int4, string, timestamp, withReplicas } from 'drizzle-orm/cockroach-core';

const usersTable = cockroachTable("users", {
  id: int4().primaryKey(),
  name: string().notNull(),
  verified: boolean().notNull().default(false),
  jsonb: jsonb().$type<string[]>(),
  createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
});

const primaryDb = drizzle("postgres://user:password@host:port/primary_db");
const read1 = drizzle("postgres://user:password@host:port/read_replica_1");
const read2 = drizzle("postgres://user:password@host:port/read_replica_2");

const db = withReplicas(primaryDb, [read1, read2]);
```

You can now use the `db` instance the same way you did before. Drizzle will 
handle the choice between read replica and the primary instance automatically

```ts
// Read from either the read1 connection or the read2 connection
await db.select().from(usersTable)

// Use the primary database for the delete operation
await db.delete(usersTable).where(eq(usersTable.id, 1))
```

You can use the `$primary` key to force using primary instances even for read operations

```ts
// read from primary
await db.$primary.select().from(usersTable);
```

With Drizzle, you can also specify custom logic for choosing read replicas. 
You can make a weighted decision or any other custom selection method for random read replica choice. 
Here is an 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 selected.

Keep in mind that you can implement any type of random selection method 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]!
});

await db.select().from(usersTable)
```


Source: https://orm.drizzle.team/docs/cockroach/relations-schema-declaration

import Tab from '@mdx/Tab.astro';
import Tabs from '@mdx/Tabs.astro';
import Callout from '@mdx/Callout.astro';
import SimpleLinkCards from '@mdx/SimpleLinkCards.astro';
import CodeTabs from "@mdx/CodeTabs.astro";
import Section from '@mdx/Section.astro';
import Flex from "@mdx/Flex.astro"
import LinksList from "@mdx/LinksList.astro"

# Drizzle Relations Fundamentals

In the world of databases, especially relational databases, the concept of relations is absolutely fundamental.
Think of "relations" as the connections and links between different pieces of data. Just like in real life, 
where people have relationships with each other, or objects are related to categories, databases use relations to model how different 
types of information are connected and work together.

### Normalization
Normalization is the process of organizing data in your database to reduce redundancy (duplication) and improve data integrity 
(accuracy and consistency). Think of it like tidying up a messy filing cabinet. Instead of having all sorts of papers 
crammed into one folder, you organize them into logical folders and categories to make everything easier to find and manage.

<Callout collapsed="Why is Normalization Important?">
- **Reduces Data Redundancy**: Imagine storing a customer's address every time they place an order. If the address changes, you'd have to update it in multiple places! Normalization helps you store information in one place and refer to it from other places, minimizing repetition.
- **Improves Data Integrity**: Less redundancy means less chance of inconsistencies. If you update an address in one place, it's updated everywhere it's needed.
- **Prevents Anomalies**: Normalization helps prevent issues like:
  1. **Insertion Anomalies**: Difficulty adding new data because you're missing related information.
  2. **Update Anomalies**: Having to update the same information in multiple rows.
  3. **Deletion Anomalies**: Accidentally losing valuable information when you delete something seemingly unrelated.
- **Easier to Understand and Maintain**: A normalized database is generally more logically structured and easier to understand, query, and modify.
</Callout>

Normalization is often described in terms of "normal forms" (1NF, 2NF, 3NF, and beyond). While the details can get quite technical, the core ideas are straightforward:

#### 1NF (First Normal Form): `Atomic Values`

**Goal**: Each column should hold a single, indivisible value. No repeating groups of data within a single cell

**Example**: Instead of having a single `address` column that stores `123 Main St, City, USA`, you'd 
break it down into separate columns: `street_address`, `city`, `state`, `zip_code`.

```sql
-- Unnormalized (violates 1NF)
CREATE TABLE "Customers_Unnormalized" (
    "customer_id" INT4 PRIMARY KEY,
    "name" VARCHAR(255),
    "address" VARCHAR(255) -- Problem: Multiple pieces of info in one column
);

-- Normalized to 1NF
CREATE TABLE "Customers_1NF" (
    "customer_id" INT4 PRIMARY KEY,
    "name" VARCHAR(255),
    "street_address" VARCHAR(255),
    "city" VARCHAR(255),
    "state" VARCHAR(255),
    "zip_code" VARCHAR(10)
);
```

#### 2NF (Second Normal Form): `Eliminate Redundant Data Dependent on Part of the Key`

**Goal**: Applies when you have a table with a composite primary key (a primary key made up of two or more columns). 
2NF ensures that all non-key attributes are fully dependent on the entire composite primary key, not just part of it.

Imagine we have a table called `order_items`. This table tracks items within orders, and we use a composite primary key (`order_id`, `product_id`) 
because a single order can have multiple of the same product (though in this simplified example, let's assume each product appears only 
once per order for clarity, but the composite key logic still applies).

<Callout collapsed="Expand for visual example">
```sql
CREATE TABLE "OrderItems_Unnormalized" (
    "order_id" INT4,
    "product_id" VARCHAR(10),
    "product_name" VARCHAR(100),
    "product_price" DECIMAL(10, 2),
    "quantity" INT4,
    "order_date" DATE,
    PRIMARY KEY ("order_id", "product_id") -- Composite Primary Key
);

INSERT INTO "OrderItems_Unnormalized" ("order_id", "product_id", "product_name", "product_price", "quantity", "order_date") VALUES
(101, 'A123', 'Laptop', 1200.00, 1, '2023-10-27'),
(101, 'B456', 'Mouse', 25.00, 2, '2023-10-27'),
(102, 'A123', 'Laptop', 1200.00, 1, '2023-10-28'),
(103, 'C789', 'Keyboard', 75.00, 1, '2023-10-29');
```
```
+------------------------------------------------------------------------------------+
| OrderItems_Unnormalized                                                            |
+------------------------------------------------------------------------------------+
| PK (order_id, product_id) | product_name | product_price | quantity | order_date   |
+------------------------------------------------------------------------------------+
| 101, A123               | Laptop       | 1200.00       | 1        | 2023-10-27     |
| 101, B456               | Mouse        | 25.00         | 2        | 2023-10-27     |
| 102, A123               | Laptop       | 1200.00       | 1        | 2023-10-28     |
| 103, C789               | Keyboard     | 75.00         | 1        | 2023-10-29     |
+------------------------------------------------------------------------------------+
```
</Callout>

**Problem**: Notice that `product_name` and `product_price` are repeated whenever the same `product_id` appears in different orders. 
These attributes are only dependent on `product_id`, which is part of the composite primary key (`order_id`, `product_id`), but not the entire key. 
This is a partial dependency.

To achieve 2NF, we need to remove the partially dependent attributes (`product_name`, `product_price`) and place them in a separate table where they are 
fully dependent on the primary key of that new table.

<Callout collapsed="Normalization to 2NF: Visual explanation">
```
+-------------------+     1:M     +---------------------------+
| Products          | <---------- | OrderItems_2NF            |
+-------------------+             +---------------------------+
| PK product_id     |             | PK (order_id, product_id) |
| product_name      |             | quantity                  |
| product_price     |             | order_date                |
+-------------------+             | FK product_id             |
                                  +---------------------------+
```
```sql
CREATE TABLE "Products" (
    "product_id" VARCHAR(10) PRIMARY KEY,
    "product_name" VARCHAR(100),
    "product_price" DECIMAL(10, 2)
);

CREATE TABLE "OrderItems_2NF" (
    "order_id" INT4,
    "product_id" VARCHAR(10),
    "quantity" INT4,
    "order_date" DATE,
    PRIMARY KEY ("order_id", "product_id"), -- Composite Primary Key remains
    FOREIGN KEY ("product_id") REFERENCES "Products"("product_id") -- Foreign Key to Products
);

-- Insert data into Products
INSERT INTO "Products" ("product_id", "product_name", "product_price") VALUES
('A123', 'Laptop', 1200.00),
('B456', 'Mouse', 25.00),
('C789', 'Keyboard', 75.00);

-- Insert data into OrderItems_2NF (referencing Products)
INSERT INTO "OrderItems_2NF" ("order_id", "product_id", "quantity", "order_date") VALUES
(101, 'A123', 1, '2023-10-27'),
(101, 'B456', 2, '2023-10-27'),
(102, 'A123', 1, '2023-10-28'),
(103, 'C789', 1, '2023-10-29');
```
</Callout>

#### 3NF (Third Normal Form): `Eliminate Redundant Data Dependent on Non-Key Attributes`

**Goal**: Remove data that is dependent on other non-key attributes. This is about eliminating transitive dependencies.

**Problem**: Let's say we have a `suppliers` table. We store supplier information, including their `zip_code`, `city`, and `state`. `supplier_id` is the primary key.

<Callout collapsed="">
```sql
CREATE TABLE "suppliers" (
    "supplier_id" VARCHAR(10) PRIMARY KEY,
    "supplier_name" VARCHAR(255),
    "zip_code" VARCHAR(10),
    "city" VARCHAR(100),
    "state" VARCHAR(50)
);

INSERT INTO "suppliers" ("supplier_id", "supplier_name", "zip_code", "city", "state") VALUES
('S1', 'Acme Corp', '12345', 'Anytown', 'NY'),
('S2', 'Beta Inc', '67890', 'Otherville', 'CA'),
('S3', 'Gamma Ltd', '12345', 'Anytown', 'NY');
```
```
+---------------------------------------------------------------+
| suppliers                                                     |
+---------------------------------------------------------------+
| PK supplier_id | supplier_name | zip_code | city      | state |
+---------------------------------------------------------------+
| S1             | Acme Corp     | 12345    | Anytown    | NY   |
| S2             | Beta Inc      | 67890    | Otherville | CA   |
| S3             | Gamma Ltd     | 12345    | Anytown    | NY   |
+---------------------------------------------------------------+
```
</Callout>

**Solution**: To achieve 3NF, we remove the attributes dependent on the non-key attribute (`city`, `state` dependent on `zip_code`) and put 
them into a separate table keyed by the non-key attribute itself (`zip_code`).

<Callout collapsed="Normalization to 3NF: Visual explanation">
```
+-------------------+     1:M     +--------------------+
| zip_codes         | <---------- | suppliers          |
+-------------------+             +--------------------+
| PK zip_code       |             | PK supplier_id     |
| city              |             | supplier_name      |
| state             |             | FK zip_code        |
+-------------------+             +--------------------+
```
```sql
CREATE TABLE "zip_codes" (
    "zip_code" VARCHAR(10) PRIMARY KEY,
    "city" VARCHAR(100),
    "state" VARCHAR(50)
);

CREATE TABLE "suppliers" (
    "supplier_id" VARCHAR(10) PRIMARY KEY,
    "supplier_name" VARCHAR(255),
    "zip_code" VARCHAR(10), -- Foreign Key to zip_codes
    FOREIGN KEY ("zip_code") REFERENCES "zip_codes"("zip_code")
);

-- Insert data into zip_codes
INSERT INTO "zip_codes" ("zip_code", "city", "state") VALUES
('12345', 'Anytown', 'NY'),
('67890', 'Otherville', 'CA');

-- Insert data into suppliers (referencing zip_codes)
INSERT INTO "suppliers" ("supplier_id", "supplier_name", "zip_code") VALUES
('S1', 'Acme Corp', '12345'),
('S2', 'Beta Inc', '67890'),
('S3', 'Gamma Ltd', '12345');
```
</Callout>

<Callout title="Good to know">
There are additional normal forms, such as `4NF`, `5NF`, `6NF`, `EKNF`, `ETNF`, and `DKNF`. We won't cover these here, but we will create a 
dedicated set of tutorials for them in our guides and tutorials section.
</Callout>

### Database Relationships
#### One-to-One

In a one-to-one relationship, each record in `table A` is related to at most one record in `table B`, and each record in `table B` is
related to at most one record in `table A`. It's a very direct, exclusive pairing.

<Callout collapsed="Use Cases & Examples">
1. **User Profiles and User Account Details**: Think of a website. Each user account (in a Users table) might have exactly one user profile (in a UserProfiles table) containing more detailed information.
2. **Employees and Parking Spaces**: An Employees table and a ParkingSpaces table. Each employee might be assigned at most one parking space, and each parking space is assigned to at most one employee.
3. **Splitting Tables for Organization**: Sometimes, you might split a very wide table into two for better organization or security reasons, maintaining a 1-1 relationship between them.

```
Table A (One Side)      Table B (One Side)
+---------+             +---------+
| PK (A)  | <---------> | FK (A)  | (Foreign Key referencing Table A)
| ...     |             | ...     |
+---------+             +---------+
```
</Callout>


#### One-to-Many

In a one-to-many relationship, one record in `table A` can be related to many records in `table B`, but each 
record in `table B` is related to at most one record in `table A`. Think of it as a "parent-child" relationship.

<Callout collapsed="Use Cases & Examples">
1. **Customers and Orders**: One customer can place many orders, but each order belongs to only one customer.
2. **Authors and Books**: One author can write many books, but (let's simplify for now and say) each book is written by one primary author.
3. **Departments and Employees**: One department can have many employees, but each employee belongs to only one department.

```
Table A (One Side)      Table B (Many Side)
+---------+             +---------+
| PK (A)  | ----------> | FK (A)  | (Foreign Key referencing Table A)
| ...     |             | ...     |
+---------+             +---------+
     (One)                  (Many)
```
</Callout>

#### Many-to-Many

In a many-to-many relationship, one record in `table A` can be related to many records in `table B`, and one 
record in `table B` can be related to many records in `table A`. It's a more complex, bidirectional relationship.

<Callout collapsed="Use Cases & Examples">
1. **Students and Courses**: One student can enroll in many courses, and one course can have many students enrolled.
2. **Products and Categories**: One product can belong to multiple categories (e.g., a "T-shirt" can be
in "Clothing" and "Summer Wear" categories), and one category can contain many products.
3. **Authors and Books**: A book can be written by multiple authors, and an author can write multiple books.

```
Table A (Many Side)    Junction Table      Table B (Many Side)
+---------+          +-------------+     +---------+
| PK (A)  | -------->| FK (A)      | <----| FK (B)  |
| ...     |          | FK (B)      |     | ...     |
+---------+          +-------------+     +---------+
     (Many)             (Junction)          (Many)
```
</Callout>

Many-to-many relationships are not directly implemented with foreign keys between the two main tables. 
Instead, you need a `junction` table (also called an associative table or bridging table). 
This table acts as an intermediary to link records from both tables.

```sql
-- Table for Students (Many side)
CREATE TABLE "students" (
    "id" INT4 PRIMARY KEY,
    "name" VARCHAR(255)
);

-- Table for Courses (Many side)
CREATE TABLE "courses" (
    "id" INT4 PRIMARY KEY,
    "name" VARCHAR(255),
    "credits" INT4
);

-- Junction Table: Enrollments (Connects Students and Courses - M-M relationship)
CREATE TABLE "enrollments" (
    "id" INT4 GENERATED ALWAYS AS IDENTITY PRIMARY KEY, -- Optional, but good practice for junction tables
    "student_id" INT4,
    "course_id" INT4,
    "enrollment_date" DATE,
    -- Composite Foreign Keys (often part of a composite primary key or unique constraint)
    FOREIGN KEY ("student_id") REFERENCES "students"("id"),
    FOREIGN KEY ("course_id") REFERENCES "courses"("id"),
    UNIQUE ("student_id", "course_id") -- Prevent duplicate enrollments for the same student and course
);
```

### Why Foreign Keys?

You might think of foreign key constraints as simply a way to validate data - ensuring 
that when you enter a value in a foreign key column, that value actually exists in the primary key 
column of another table. And you'd be partially right! This value checking is the mechanism foreign keys use.

But it's crucial to understand that this validation is not the end goal, it's the means 
to a much larger purpose. Foreign key constraints are fundamentally about:

<Callout collapsed="1. Explicitly Defining and Enforcing Relationships">

We've discussed relationships like `One-to-Many` between Customers and Orders. 
A foreign key is the SQL language's way of telling the database: 

> Hey database, I want to enforce a 1-M relationship here. Every value in the customer_id column of the
Orders table must correspond to a valid customer_id in the Customers table.

It's not just a suggestion; it's a constraint the database actively enforces. 
The database becomes relationship-aware because of the foreign key.
</Callout>

<Callout collapsed="2. Maintaining Referential Integrity">
- This is the core of "data integrity" in the context of relationships. Referential integrity means 
that relationships between tables remain consistent and valid over time.
- Foreign keys prevent orphaned records. What's an orphaned record? In our Customer-Order example, 
an order that exists in the Orders table but doesn't have a corresponding customer in the Customers 
table would be an orphan. Foreign keys prevent this from happening (or control what happens 
if you try to delete a customer with orders - via CASCADE, SET NULL, etc.).
- Why is preventing orphans important? Orphaned records break the logical structure of your data. 
If you have an order without a customer, you lose crucial context. Queries become unreliable, reports
 become inaccurate, and your application's logic can break down.

**Example**:
```
Without a foreign key, you could accidentally delete a customer from the Customers 
table while their orders still exist in the Orders table. Suddenly, you have orders that point to 
a customer that no longer exists! A foreign key constraint prevents this data inconsistency.
```
</Callout>

<Callout collapsed="3. Facilitating Database Design and Understanding">
- Foreign keys are not just about technical enforcement; they are also a crucial part of database design documentation.
- When you see a foreign key in a database schema, it immediately tells you: 
`Table 'X' is related to Table 'Y' in this way.` It's a clear visual and structural indicator of relationships.
- This makes databases easier to understand, maintain, and evolve over time. New developers can quickly 
grasp how different parts of the database are connected.
</Callout>

In essence, foreign key constraints are not just about checking values; they are about:

1. Defining the rules of your data relationships
2. Actively enforcing those rules at the database level
3. Guaranteeing data integrity and consistency within those relationships
4. Making your database more robust, reliable, and understandable

### Why NOT Foreign Keys?

While highly beneficial, there are some scenarios where you might reconsider or use Foreign Keys with caution. 
These are typically edge cases and often involve trade-offs.

<Callout collapsed="1. Performance Overhead in Very High-Write Environments">
- **Scenario**: Extremely high-volume transactional systems (e.g., real-time logging, very high-frequency trading
platforms, massive IoT data ingestion).
- **Explanation**: Every time you insert or update data in a table with a foreign key, the database system 
needs to perform checks to ensure referential integrity. In extremely high-write scenarios, these 
checks can introduce a small but potentially noticeable performance overhead.
</Callout>

<Callout collapsed="2. Distributed Database Systems and Cross-Node Foreign Keys:">
- **Scenario**: Systems where data is distributed across multiple database nodes or clusters (common in sharded databases, cloud environments, and microservices).
- **Explanation**:  Cross-node foreign keys can introduce significant complexity and performance overhead. Validating referential integrity requires communication between nodes, leading to increased latency. Distributed transactions needed to maintain consistency are also more complex and can be less performant than local transactions. In such architectures, application-level data integrity checks or eventual consistency models might be considered alternatives.
</Callout>

<Callout collapsed="3. Legacy Systems and Data Integration with Non-Relational Data:">
- **Scenario**: Integrating a relational database with older legacy systems or non-relational data stores (e.g., NoSQL, flat files, external APIs).
- **Explanation**:  Legacy systems or non-relational data might not consistently adhere to the referential integrity rules enforced by foreign keys.  Imposing foreign keys in such scenarios can lead to data import issues, data inconsistencies, and might necessitate complex data transformation or application-level integrity management instead. You might need to carefully evaluate the data quality and consistency of the external sources and potentially rely on application logic or ETL processes to ensure data integrity instead of strictly enforcing foreign keys at the database level.
</Callout>

You can also check out some great explanations from the PlanetScale team in their [article](https://planetscale.com/docs/learn/operating-without-foreign-key-constraints#why-does-planetscale-not-recommend-constraints)

### Polymorphic Relations

Polymorphic relationships are a more advanced concept that allows a single relationship to point to 
different types of entities or tables. It's about creating more flexible and adaptable relationships when 
you have different kinds of data that share some commonality.

Imagine you have an `activities` log. An activity could be a `comment` a `like` or a `share`.
Each of these `activity` types has different details. Instead of creating separate tables and 
relationships for each activity type and the things they relate to, you might use a polymorphic approach.

<Callout collapsed="Common Scenarios & Examples">
- **Comments/Reviews**: A "Comment" might be related to different types of content: articles, products, videos, etc. 
Instead of having separate article_id, product_id, video_id columns in a Comments table, you can use a 
polymorphic relationship.
```
+---------------------+
| **Comments**        |
+---------------------+
| PK comment_id       |
| commentable_type    | ------>  [Polymorphic Relationship]
| commentable_id      | -------->
| user_id             |
| comment_text        |
| ...                 |
+---------------------+
          ^
          |
+---------------------+    +---------------------+    +---------------------+
| **Articles**        |    | **Products**        |    | **Videos**          |
+---------------------+    +---------------------+    +---------------------+
| PK article_id       |    | PK product_id       |    | PK video_id         |
| ...                 |    | ...                 |    | ...                 |
+---------------------+    +---------------------+    +---------------------+
```
- **Notifications:** A notification could be related to a user, an order, a system event, etc.
```
+----------------------+
| **Notifications**    |
+----------------------+
| PK notification_id  |
| notifiable_type     | ------>  [Polymorphic Relationship]
| notifiable_id       | -------->
| user_id             |
| message             |
| ...                  |
+----------------------+
           ^
           |
+---------------------+    +---------------------+    +-----------------------+
| **Users**           |    | **Orders**          |    | **System Events**     |
+---------------------+    +---------------------+    +-----------------------+
| PK user_id          |    | PK order_id         |    | PK event_id           |
| ...                 |    | ...                 |    | ...                   |
+---------------------+    +---------------------+    +-----------------------+
```
</Callout>

Polymorphic relationships are more complex and are often handled at the application level or 
using more advanced database features (depending on the specific database system). Standard SQL doesn't 
have direct, built-in support for enforcing polymorphic foreign key constraints in the same way as regular foreign keys.

Source: https://orm.drizzle.team/docs/cockroach/relations

import Tab from '@mdx/Tab.astro';
import Tabs from '@mdx/Tabs.astro';
import IsSupportedChipGroup from '@mdx/IsSupportedChipGroup.astro';
import Callout from '@mdx/Callout.astro';
import Section from '@mdx/Section.astro';

import CodeTab from '@mdx/CodeTab.astro';
import CodeTabs from '@mdx/CodeTabs.astro';

# Drizzle soft relations
The sole purpose of Drizzle relations is to let you query your relational data in the most simple and consise way:

<CodeTabs items={["Relational queries", "Select with joins"]}>
<Section>
```ts
import * as schema from './schema';
import { drizzle } from 'drizzle-orm/cockroach';

const db = drizzle({ client, schema });

const result = await db._query.users.findMany({
  with: {
    posts: true,
  },
});
```
```ts
[{
  id: 10,
  name: "Dan",
  posts: [
    {
      id: 1,
      content: "SQL is awesome",
      authorId: 10,
    },
    {
      id: 2,
      content: "But check relational queries",
      authorId: 10,
    }
  ]
}]
```
</Section>
<Section>
```ts
import { drizzle } from 'drizzle-orm/cockroach';
import { eq } from 'drizzle-orm';
import { posts, users } from './schema';

const db = drizzle(client);

const res = await db.select()
                    .from(users)
                    .leftJoin(posts, eq(posts.authorId, users.id))
                    .orderBy(users.id)
const mappedResult =  
```
</Section>
</CodeTabs>


### One-to-one
Drizzle ORM provides you an API to define `one-to-one` relations between tables with the `relations` operator.

An example of a `one-to-one` relation between users and users, where a user can invite another (this example uses a self reference):

```typescript copy {10-15}
import { cockroachTable, int4, text, } from 'drizzle-orm/cockroach-core';
import { relations } from 'drizzle-orm/_relations';

export const users = cockroachTable('users', {
	id: int4().primaryKey(),
	name: text(),
	invitedBy: int4('invited_by'),
});

export const usersRelations = relations(users, ({ one }) => ({
	invitee: one(users, {
		fields: [users.invitedBy],
		references: [users.id],
	}),
}));
```

Another example would be a user having a profile information stored in separate table. In this case, because the foreign key is stored in the "profile_info" table, the user relation have neither fields or references. This tells Typescript that `user.profileInfo` is nullable:

```typescript copy {9-17}
import { cockroachTable, int4, text, jsonb } from 'drizzle-orm/cockroach-core';
import { relations } from 'drizzle-orm/_relations';

export const users = cockroachTable('users', {
	id: int4('id').primaryKey(),
	name: text('name'),
});

export const usersRelations = relations(users, ({ one }) => ({
	profileInfo: one(profileInfo),
}));

export const profileInfo = cockroachTable('profile_info', {
	id: int4('id').primaryKey(),
	userId: int4('user_id').references(() => users.id),
	metadata: jsonb('metadata'),
});

export const profileInfoRelations = relations(profileInfo, ({ one }) => ({
	user: one(users, { fields: [profileInfo.userId], references: [users.id] }),
}));

const user = await queryUserWithProfileInfo();
//____^? type { id: number, profileInfo: { ... } | null  }
```

### One-to-many
Drizzle ORM provides you an API to define `one-to-many` relations between tables with `relations` operator. 

Example of `one-to-many` relation between users and posts they've written:

```typescript copy {9-11, 19-24}
import { cockroachTable, int4, text } from 'drizzle-orm/cockroach-core';
import { relations } from 'drizzle-orm/_relations';

export const users = cockroachTable('users', {
	id: int4('id').primaryKey(),
	name: text('name'),
});

export const usersRelations = relations(users, ({ many }) => ({
	posts: many(posts),
}));

export const posts = cockroachTable('posts', {
	id: int4('id').primaryKey(),
	content: text('content'),
	authorId: int4('author_id'),
});

export const postsRelations = relations(posts, ({ one }) => ({
	author: one(users, {
		fields: [posts.authorId],
		references: [users.id],
	}),
}));
```

Now lets add comments to the posts:
```typescript copy {14,17-22,24-29}
...

export const posts = cockroachTable('posts', {
	id: int4('id').primaryKey(),
	content: text('content'),
	authorId: int4('author_id'),
});

export const postsRelations = relations(posts, ({ one, many }) => ({
	author: one(users, {
		fields: [posts.authorId],
		references: [users.id],
	}),
	comments: many(comments)
}));

export const comments = cockroachTable('comments', {
	id: int4('id').primaryKey(),
	text: text('text'),
	authorId: int4('author_id'),
	postId: int4('post_id'),
});

export const commentsRelations = relations(comments, ({ one }) => ({
	post: one(posts, {
		fields: [comments.postId],
		references: [posts.id],
	}),
}));
```


### Many-to-many
Drizzle ORM provides you an API to define `many-to-many` relations between tables through so called `junction` or `join` tables,
they have to be explicitly defined and store associations between related tables.  
  
Example of `many-to-many` relation between users and groups:
```typescript copy {9-11, 18-20, 37-46}
import { relations } from 'drizzle-orm/_relations';
import { int4, cockroachTable, primaryKey, text } from 'drizzle-orm/cockroach-core';

export const users = cockroachTable('users', {
  id: int4('id').primaryKey(),
  name: text('name'),
});

export const usersRelations = relations(users, ({ many }) => ({
  usersToGroups: many(usersToGroups),
}));

export const groups = cockroachTable('groups', {
  id: int4('id').primaryKey(),
  name: text('name'),
});

export const groupsRelations = relations(groups, ({ many }) => ({
  usersToGroups: many(usersToGroups),
}));

export const usersToGroups = cockroachTable(
  'users_to_groups',
  {
    userId: int4('user_id')
      .notNull()
      .references(() => users.id),
    groupId: int4('group_id')
      .notNull()
      .references(() => groups.id),
  },
  (t) => [
		primaryKey({ columns: [t.userId, t.groupId] })
	],
);

export const usersToGroupsRelations = relations(usersToGroups, ({ one }) => ({
  group: one(groups, {
    fields: [usersToGroups.groupId],
    references: [groups.id],
  }),
  user: one(users, {
    fields: [usersToGroups.userId],
    references: [users.id],
  }),
}));
```

### Foreign keys

You might've noticed that `relations` look similar to foreign keys — they even have a `references` property. So what's the difference?

While foreign keys serve a similar purpose, defining relations between tables, they work on a different level compared to `relations`.

Foreign keys are a database level constraint, they are checked on every `insert`/`update`/`delete` operation and throw an error if a constraint is violated.
On the other hand, `relations` are a higher level abstraction, they are used to define relations between tables on the application level only.
They do not affect the database schema in any way and do not create foreign keys implicitly.

What this means is `relations` and foreign keys can be used together, but they are not dependent on each other.
You can define `relations` without using foreign keys (and vice versa), which allows them to be used with databases that do not support foreign keys.

The following two examples will work exactly the same in terms of querying the data using Drizzle relational queries.
<CodeTabs items={["schema1.ts", "schema2.ts"]}>
<CodeTab>
```ts {15}
export const users = cockroachTable('users', {
	id: int4('id').primaryKey(),
	name: text('name'),
});

export const profileInfo = cockroachTable('profile_info', {
	id: int4('id').primaryKey(),
	userId: int4("user_id"),
	metadata: jsonb("metadata"),
});

export const profileInfoRelations = relations(profileInfo, ({ one }) => ({
  user: one(users, {
    fields: [profileInfo.userId],
    references: [users.id],
  }),
}));
```
</CodeTab>
<CodeTab>
```ts {15}
export const users = cockroachTable('users', {
	id: int4('id').primaryKey(),
	name: text('name'),
});

export const profileInfo = cockroachTable('profile_info', {
	id: int4('id').primaryKey(),
	userId: int4("user_id").references(() => users.id),
	metadata: jsonb("metadata"),
});

export const profileInfoRelations = relations(profileInfo, ({ one }) => ({
  user: one(users, {
    fields: [profileInfo.userId],
    references: [users.id],
  }),
}));
```
</CodeTab>
</CodeTabs>

### Foreign key actions

For more information check the [CockroachDB foreign keys docs](https://www.cockroachlabs.com/docs/v26.2/foreign-key.html)

You can specify actions that should occur when the referenced data in the parent table is modified. These actions are known as "foreign key actions." CockroachDB provides several options for these actions.

On Delete/ Update Actions

- `CASCADE`: When a row in the parent table is deleted, all corresponding rows in the child table will also be deleted. This ensures that no orphaned rows exist in the child table.

- `NO ACTION`: This is the default action. It prevents the deletion of a row in the parent table if there are related rows in the child table. The DELETE operation in the parent table will fail.

- `RESTRICT`: Similar to NO ACTION, it prevents the deletion of a parent row if there are dependent rows in the child table. It is essentially the same as NO ACTION and included for compatibility reasons.

- `SET DEFAULT`: If a row in the parent table is deleted, the foreign key column in the child table will be set to its default value if it has one. If it doesn't have a default value, the DELETE operation will fail.

- `SET NULL`: When a row in the parent table is deleted, the foreign key column in the child table will be set to NULL. This action assumes that the foreign key column in the child table allows NULL values.

> Analogous to ON DELETE there is also ON UPDATE which is invoked when a referenced column is changed (updated). The possible actions are the same, except that column lists cannot be specified for SET NULL and SET DEFAULT. In this case, CASCADE means that the updated values of the referenced column(s) should be copied into the referencing row(s).
in drizzle you can add foreign key action using `references()` second argument.

type of the actions

```typescript
export type UpdateDeleteAction = 'cascade' | 'restrict' | 'no action' | 'set null' | 'set default';

// second argument of references interface
actions?: {
		onUpdate?: UpdateDeleteAction;
		onDelete?: UpdateDeleteAction;
	} | undefined
```

In the following example, adding `onDelete: 'cascade'` to the author field on the `posts` schema means that deleting the `user` will also delete all related Post records.


```typescript {11}
import { cockroachTable, int4, text } from 'drizzle-orm/cockroach-core';

export const users = cockroachTable('users', {
	id: int4().primaryKey(),
	name: text(),
});

export const posts = cockroachTable('posts', {
	id: int4().primaryKey(),
	name: text(),
	author: int4().references(() => users.id, { onDelete: 'cascade' }).notNull(),
});
```

For constraints specified with the `foreignKey` operator, foreign key actions are defined with the syntax:

```typescript {18-19}
import { foreignKey, cockroachTable, int4, text } from 'drizzle-orm/cockroach-core';

export const users = cockroachTable('users', {
	id: int4().primaryKey(),
	name: text(),
});

export const posts = cockroachTable('posts', {
	id: int4().primaryKey(),
	name: text(),
	author: int4().notNull(),
}, (table) => [
	foreignKey({
		name: "author_fk",
		columns: [table.author],
		foreignColumns: [users.id],
	})
		.onDelete('cascade')
		.onUpdate('cascade')
]);
```

### Disambiguating relations

Drizzle also provides the `relationName` option as a way to disambiguate
relations when you define multiple of them between the same two tables. For
example, if you define a `posts` table that has the `author` and `reviewer`
relations.

```ts {9-12, 21-32}
import { cockroachTable, int4, text } from 'drizzle-orm/cockroach-core';
import { relations } from 'drizzle-orm/_relations';
 
export const users = cockroachTable('users', {
	id: int4().primaryKey(),
	name: text(),
});
 
export const usersRelations = relations(users, ({ many }) => ({
	author: many(posts, { relationName: 'author' }),
	reviewer: many(posts, { relationName: 'reviewer' }),
}));
 
export const posts = cockroachTable('posts', {
	id: int4().primaryKey(),
	content: text(),
	authorId: int4('author_id'),
	reviewerId: int4('reviewer_id'),
});
 
export const postsRelations = relations(posts, ({ one }) => ({
	author: one(users, {
		fields: [posts.authorId],
		references: [users.id],
		relationName: 'author',
	}),
	reviewer: one(users, {
		fields: [posts.reviewerId],
		references: [users.id],
		relationName: 'reviewer',
	}),
}));
```


Source: https://orm.drizzle.team/docs/cockroach/rqb

import Callout from '@mdx/Callout.astro';
import CodeTabs from '@mdx/CodeTabs.astro';
import CodeTab from '@mdx/CodeTab.astro';
import Section from '@mdx/Section.astro';

# Drizzle Queries

Drizzle ORM is designed to be a thin typed layer on top of SQL. 
We truly believe we've designed the best way to operate an SQL database from TypeScript and it's time to make it better.  
  
Relational queries are meant to provide you with a great developer experience for querying 
nested relational data from an SQL database, avoiding multiple joins and complex data mappings.  

It is an extension to the existing schema definition and query builder. 
You can opt-in to use it based on your needs. 
We've made sure you have both the best-in-class developer experience and performance.  

<CodeTabs items={["index.ts", "schema.ts"]}>
	<CodeTab>
	```typescript copy /schema/3
	import * as schema from './schema';
	import { drizzle } from 'drizzle-orm/cockroach';

	const db = drizzle({ schema });

	const result = await db._query.users.findMany({
		with: {
			posts: true			
		},
	});
	```

	```ts
	[{
		id: 10,
		name: "Dan",
		posts: [
			{
				id: 1,
				content: "SQL is awesome",
				authorId: 10,
			},
			{
				id: 2,
				content: "But check relational queries",
				authorId: 10,
			}
		]
	}]
	```
	</CodeTab>

	```typescript copy
	import { int4, string, cockroachTable } from 'drizzle-orm/cockroach-core';
	import { relations } from 'drizzle-orm/_relations';

	export const users = cockroachTable('users', {
		id: int4().primaryKey(),
		name: string().notNull(),
	});

	export const usersRelations = relations(users, ({ many }) => ({
		posts: many(posts),
	}));

	export const posts = cockroachTable('posts', {
		id: int4().primaryKey(),
		content: string('content').notNull(),
		authorId: int4('author_id').notNull(),
	});

	export const postsRelations = relations(posts, ({ one }) => ({
		author: one(users, { fields: [posts.authorId], references: [users.id] }),
	}));
	```
</CodeTabs>

⚠️ If you have SQL schema declared in multiple files you can do it like that
<CodeTabs items={["index.ts", "schema1.ts", "schema2.ts"]}>
	```typescript copy /schema/3
	import * as schema1 from './schema1';
	import * as schema2 from './schema2';
	import { drizzle } from 'drizzle-orm/cockroach';

	const db = drizzle({ schema: { ...schema1, ...schema2 } });

	const result = await db._query.users.findMany({
		with: {
			posts: true			
		},
	});
	```
	
	```ts
	// schema declaration in the first file
	```
	```ts
	// schema declaration in the second file
	```
</CodeTabs>

## Querying
Relational queries are an extension to Drizzle's original **[query builder](/docs/cockroach/select)**.
You need to provide all `tables` and `relations` from your schema file/files upon `drizzle()` 
initialization and then just use the `db._query` API.
<Callout type="info" emoji="ℹ️">
	`drizzle` import path depends on the **[database driver](/docs/cockroach/connect-overview)** you're using.
</Callout>
<CodeTabs items={["index.ts", "schema.ts"]}>
<CodeTab>
```ts
import * as schema from './schema';
import { drizzle } from 'drizzle-orm/cockroach';

const db = drizzle({ schema });

await db._query.users.findMany(...);
```
```ts
// if you have schema in multiple files
import * as schema1 from './schema1';
import * as schema2 from './schema2';
import { drizzle } from 'drizzle-orm/cockroach';

const db = drizzle({ schema: { ...schema1, ...schema2 } });

await db._query.users.findMany(...);
```
</CodeTab>
```typescript copy
	import { type AnyCockroachColumn, boolean, int4, cockroachTable, primaryKey, string, timestamp } from 'drizzle-orm/cockroach-core';

	import { relations } from 'drizzle-orm/_relations';

	export const users = cockroachTable('users', {
		id: int4('id').primaryKey(),
		name: string('name').notNull(),
		verified: boolean('verified').notNull(),
		invitedBy: int4('invited_by').references((): AnyCockroachColumn => users.id),
	});

	export const usersRelations = relations(users, ({ one, many }) => ({
		invitee: one(users, { fields: [users.invitedBy], references: [users.id] }),
		usersToGroups: many(usersToGroups),
		posts: many(posts),
	}));

	export const groups = cockroachTable('groups', {
		id: int4('id').primaryKey(),
		name: string('name').notNull(),
		description: string('description'),
	});

	export const groupsRelations = relations(groups, ({ many }) => ({
		usersToGroups: many(usersToGroups),
	}));

	export const usersToGroups = cockroachTable('users_to_groups', {
		id: int4('id').primaryKey(),
		userId: int4('user_id').notNull().references(() => users.id),
		groupId: int4('group_id').notNull().references(() => groups.id),
	}, (t) => [
		primaryKey({ columns: [t.userId, t.groupId] })
	]);

	export const usersToGroupsRelations = relations(usersToGroups, ({ one }) => ({
		group: one(groups, { fields: [usersToGroups.groupId], references: [groups.id] }),
		user: one(users, { fields: [usersToGroups.userId], references: [users.id] }),
	}));

	export const posts = cockroachTable('posts', {
		id: int4('id').primaryKey(),
		content: string('content').notNull(),
		authorId: int4('author_id').references(() => users.id),
		createdAt: timestamp('created_at', { withTimezone: true }).notNull().defaultNow(),
	});

	export const postsRelations = relations(posts, ({ one, many }) => ({
		author: one(users, { fields: [posts.authorId], references: [users.id] }),
		comments: many(comments),
	}));

	export const comments = cockroachTable('comments', {
		id: int4('id').primaryKey(),
		content: string('content').notNull(),
		creator: int4('creator').references(() => users.id),
		postId: int4('post_id').references(() => posts.id),
		createdAt: timestamp('created_at', { withTimezone: true }).notNull().defaultNow(),
	});

	export const commentsRelations = relations(comments, ({ one, many }) => ({
		post: one(posts, { fields: [comments.postId], references: [posts.id] }),
		author: one(users, { fields: [comments.creator], references: [users.id] }),
		likes: many(commentLikes),
	}));

	export const commentLikes = cockroachTable('comment_likes', {
		id: int4('id').primaryKey(),
		creator: int4('creator').references(() => users.id),
		commentId: int4('comment_id').references(() => comments.id),
		createdAt: timestamp('created_at', { withTimezone: true }).notNull().defaultNow(),
	});

	export const commentLikesRelations = relations(commentLikes, ({ one }) => ({
		comment: one(comments, { fields: [commentLikes.commentId], references: [comments.id] }),
		author: one(users, { fields: [commentLikes.creator], references: [users.id] }),
	}));
```
</CodeTabs>

Drizzle provides `.findMany()` and `.findFirst()` APIs.
### Find many
<Section>
```typescript copy
const users = await db._query.users.findMany();
```
```ts
// result type
const result: {
	id: number;
	name: string;
	verified: boolean;
	invitedBy: number | null;
}[];
```
</Section>

### Find first
<Callout>
  `.findFirst()` will add `limit 1` to the query.
</Callout>
<Section>
```typescript copy
const user = await db._query.users.findFirst();
```
```ts
// result type
const result: {
	id: number;
	name: string;
	verified: boolean;
	invitedBy: number | null;
};
```
</Section>

### Include relations

`With` operator lets you combine data from multiple related tables and properly aggregate results.

**Getting all posts with comments:**
```typescript copy
const posts = await db._query.posts.findMany({
	with: {
		comments: true,
	},
});
```

**Getting first post with comments:**
```typescript copy
const post = await db._query.posts.findFirst({
	with: {
		comments: true,
	},
});
```

You can chain nested with statements as much as necessary.  
For any nested `with` queries Drizzle will infer types using [Core Type API](/docs/cockroach/goodies#type-api).
  
**Get all users with posts. Each post should contain a list of comments:**
```typescript copy
const users = await db._query.users.findMany({
	with: {
		posts: {
			with: {
				comments: true,
			},
		},
	},
});
```

### Partial fields select
`columns` parameter lets you include or omit columns you want to get from the database.

<Callout type="info" emoji="ℹ️">
  Drizzle performs partial selects on the query level, no additional data is transferred from the database.

  Keep in mind that **a single SQL statement is outputted by Drizzle.**
</Callout>

**Get all posts with just `id`, `content` and include `comments`:**
```typescript copy
const posts = await db._query.posts.findMany({
	columns: {
		id: true,
		content: true,
	},
	with: {
		comments: true,
	}
});
```

**Get all posts without `content`:**
```typescript copy
const posts = await db._query.posts.findMany({
	columns: {
		content: false,
	},
});
```

<Callout type="info" emoji="ℹ️">
When both `true` and `false` select options are present, all `false` options are ignored.
</Callout>

If you include the `name` field and exclude the `id` field, `id` exclusion will be redundant, 
all fields apart from `name` would be excluded anyways.  
  
**Exclude and Include fields in the same query:**
<Section>
```typescript copy
const users = await db._query.users.findMany({
	columns: {
		name: true,
		id: false // ignored
	},
});
```
```ts
// result type
const users: {
	name: string;
};
```
</Section>

**Only include columns from nested relations:**
<Section>
```typescript copy
const res = await db._query.users.findMany({
	columns: {},
	with: {
		posts: true
	}
});
```
```ts
// result type
const res: {
	posts: {
		id: number,
		string: string
	}
}[];
```
</Section>

### Nested partial fields select
Just like with **[`partial select`](#partial-select)**, you can include or exclude columns of nested relations:
```typescript copy
const posts = await db._query.posts.findMany({
	columns: {
		id: true,
		content: true,
	},
	with: {
		comments: {
			columns: {
				authorId: false
			}
		}
	}
});
```

### Select filters
Just like in our SQL-like query builder, 
relational queries API lets you define filters and conditions with the list of our **[`operators`](/docs/cockroach/operators)**.  

You can either import them from `drizzle-orm` or use from the callback syntax:
<Section>
```typescript copy
import { eq } from 'drizzle-orm';

const users = await db._query.users.findMany({
	where: eq(users.id, 1)
})
```
```ts copy
const users = await db._query.users.findMany({
	where: (users, { eq }) => eq(users.id, 1),
})
```
</Section>

Find post with `id=1` and comments that were created before particular date:
```typescript copy
await db._query.posts.findMany({
	where: (posts, { eq }) => (eq(posts.id, 1)),
	with: {
		comments: {
			where: (comments, { lt }) => lt(comments.createdAt, new Date()),
		},
	},
});
```

### Limit & Offset
Drizzle ORM provides `limit` & `offset` API for queries and for the nested entities.
  
**Find 5 posts:**
```typescript copy
await db._query.posts.findMany({
	limit: 5,
});
```

**Find posts and get 3 comments at most:**
```typescript copy
await db._query.posts.findMany({
	with: {
		comments: {
			limit: 3,
		},
	},
});
```

<Callout type="warning" emoji="⚠️">
  `offset` is only available for top level query.
</Callout>
```typescript 
await db._query.posts.findMany({
	limit: 5,
	offset: 2, // correct ✅
	with: {
		comments: {
			offset: 3, // incorrect ❌
			limit: 3,
		},
	},
});
```

Find posts with comments from the 5th to the 10th post:
```typescript copy
await db._query.posts.findMany({
	limit: 5,
  offset: 5,
	with: {
		comments: true,
	},
});
```

### Order By
Drizzle provides API for ordering in the relational query builder.  

You can use same ordering **[core API](/docs/cockroach/select#order-by)** or use
`order by` operator from the callback with no imports.  

<Section>
```typescript copy
import { desc, asc } from 'drizzle-orm';

await db._query.posts.findMany({
	orderBy: [asc(posts.id)],
});
```
```typescript copy
await db._query.posts.findMany({
	orderBy: (posts, { asc }) => [asc(posts.id)],
});
```
</Section>

**Order by `asc` + `desc`:**
```typescript copy
await db._query.posts.findMany({
	orderBy: (posts, { asc }) => [asc(posts.id)],
	with: {
		comments: {
			orderBy: (comments, { desc }) => [desc(comments.id)],
		},
	},
});
```

### Include custom fields
Relational query API lets you add custom additional fields. 
It's useful when you need to retrieve data and apply additional functions to it.
<Callout type="warning" emoji="⚠️">
	As of now aggregations are not supported in `extras`, please use **[`core queries`](/docs/cockroach/select)** for that.
</Callout>

<Section>
```typescript copy {5}
import { sql } from 'drizzle-orm';

await db._query.users.findMany({
	extras: {
		loweredName: sql`lower(${users.name})`.as('lowered_name'),
	},
})
```
```typescript copy {3}
await db._query.users.findMany({
	extras: {
		loweredName: (users, { sql }) => sql`lower(${users.name})`.as('lowered_name'),
	},
})
```
</Section>

`lowerName` as a key will be included to all fields in returned object.

<Callout type="warning" emoji="⚠️">
  You have to explicitly specify `.as("<name_for_column>")`
</Callout>

To retrieve all users with groups, but with the fullName field included (which is a concatenation of firstName and lastName), 
you can use the following query with the Drizzle relational query builder.

<Section>
```typescript copy
const res = await db._query.users.findMany({
	extras: {
		fullName: sql<string>`concat(${users.name}, " ", ${users.name})`.as('full_name'),
	},
	with: {
		usersToGroups: {
			with: {
				group: true,
			},
		},
	},
});
```
```ts
// result type
const res: {
	id: number;
	name: string;
	verified: boolean;
	invitedBy: number | null;
	fullName: string;
	usersToGroups: {
			group: {
					id: number;
					name: string;
					description: string | null;
			};
	}[];
}[];

```
</Section>

To retrieve all posts with comments and add an additional field to calculate the size of the post content and the size of each comment content:
<Section>
```typescript copy
const res = await db._query.posts.findMany({
	extras: (table, { sql }) => ({
		contentLength: (sql<number>`length(${table.content})`).as('content_length'),
	}),
	with: {
		comments: {
			extras: {
				commentSize: sql<number>`length(${comments.content})`.as('comment_size'),
			},
		},
	},
});
```
```ts
// result type
const res: {
	id: number;
	createdAt: Date;
	content: string;
	authorId: number | null;
	contentLength: number;
	comments: {
			id: number;
			createdAt: Date;
			content: string;
			creator: number | null;
			postId: number | null;
			commentSize: number;
	}[];
};
```
</Section>

### Prepared statements
Prepared statements are designed to massively improve query performance — [see here.](/docs/cockroach/perf-queries)

In this section, you can learn how to define placeholders and execute prepared statements 
using the Drizzle relational query builder.

##### **Placeholder in `where`**

<Section>
```ts copy
const prepared = db._query.users.findMany({
	where: ((users, { eq }) => eq(users.id, placeholder('id'))),
	with: {
		posts: {
			where: ((users, { eq }) => eq(users.id, placeholder('pid'))),
		},
	},
}).prepare('query_name');

const usersWithPosts = await prepared.execute({ id: 1, pid: 1 });
```
</Section>

##### **Placeholder in `limit`**

<Section>
```ts copy
const prepared = db._query.users.findMany({
	with: {
		posts: {
			limit: placeholder('limit'),
		},
	},
}).prepare('query_name');

const usersWithPosts = await prepared.execute({ limit: 1 });
```
</Section>

##### **Placeholder in `offset`**

<Section>
```ts copy
const prepared = db._query.users.findMany({
	offset: placeholder('offset'),
	with: {
		posts: true,
	},
}).prepare('query_name');

const usersWithPosts = await prepared.execute({ offset: 1 });
```
</Section>

##### **Multiple placeholders**

<Section>
```ts copy
const prepared = db._query.users.findMany({
	limit: placeholder('uLimit'),
	offset: placeholder('uOffset'),
	where: ((users, { eq, or }) => or(eq(users.id, placeholder('id')), eq(users.id, 3))),
	with: {
		posts: {
			where: ((users, { eq }) => eq(users.id, placeholder('pid'))),
			limit: placeholder('pLimit'),
		},
	},
}).prepare('query_name');

const usersWithPosts = await prepared.execute({ pLimit: 1, uLimit: 3, uOffset: 1, id: 2, pid: 6 });
```
</Section>


Source: https://orm.drizzle.team/docs/cockroach/schemas

import Section from '@mdx/Section.astro';
import Callout from '@mdx/Callout.astro';

# Table schemas

If you declare an entity within a schema, query builder will prepend schema names in queries:<br/>
`select * from "schema"."users"`

<Section>
    ```ts copy {3,5,7}
    import { int4, string, cockroachSchema } from "drizzle-orm/cockroach-core";

    export const mySchema = cockroachSchema("my_schema");

    export const colors = mySchema.enum('colors', ['red', 'green', 'blue']);

    export const mySchemaUsers = mySchema.table('users', {
      id: int4('id').primaryKey(),
      name: string('name'),
      color: colors('color').default('red'),
    });
    ```
    ```sql
    CREATE SCHEMA "my_schema";

    CREATE TYPE "my_schema"."colors" AS ENUM('red', 'green', 'blue');
	
    CREATE TABLE "my_schema"."users" (
    	"id" int4 PRIMARY KEY,
    	"name" string,
    	"color" "my_schema"."colors" DEFAULT 'red'::"my_schema"."colors"
    );
    ```
    </Section>

{/* TODO: ??? example > **Warning**
> If you will have tables with same names in different schemas then drizzle will respond with `never[]` error in result types and error from database
>
> In this case you may use [alias syntax](./joins#join-aliases-and-self-joins) */}


Source: https://orm.drizzle.team/docs/cockroach/seed-functions

import Callout from '@mdx/Callout.astro';
import Tab from "@mdx/Tab.astro";
import Tabs from "@mdx/Tabs.astro";

# Generators

<Callout title='warning'>
For now, specifying `arraySize` along with `isUnique` in generators that support it will result in unique values being generated (not unique arrays), which will then be packed into arrays.
</Callout>

## ---

### `default`

<rem025 />
Generates the same given value each time the generator is called.

|  | param          | default     | type
|:-| :--------      | :--------   | :--------
|  |`defaultValue`  |--           |`any`
|  |`arraySize`     |--           |`number`

<rem025 />

```ts 
import { seed } from "drizzle-seed";

await seed(db, schema, { count: 1000 }).refine((funcs) => ({
  posts: {
    columns: {
      content: funcs.default({
        // value you want to generate
        defaultValue: "post content",

        // number of elements in each one-dimensional array. 
        // (If specified, arrays will be generated.)
        arraySize: 3
      }),
    },
  },
}));

```

### `valuesFromArray`

<rem025 />
Generates values from given array

|  | param      | default                     | type
|:-| :--------  | :--------                   | :--------
|  |`values`    |--                           |`any[]` \| `{ weight: number; values: any[] }[]`
|  |`isUnique`  |`database column uniqueness` |`boolean`
|  |`arraySize` |--                           |`number`


<rem025 />
```ts 
import { seed } from "drizzle-seed";

await seed(db, schema, { count: 1000 }).refine((funcs) => ({
  posts: {
    columns: {
      title: funcs.valuesFromArray({
        // Array of values you want to generate (can be an array of weighted values)
        values: ["Title1", "Title2", "Title3", "Title4", "Title5"],

        // Property that controls whether the generated values will be unique or not
        isUnique: true,
        
        // number of elements in each one-dimensional array. 
        // (If specified, arrays will be generated.)
        arraySize: 3
      }),
    },
  },
}));

```

### `intPrimaryKey`

<rem025 />
Generates sequential integers starting from 1.

|  | param      | default    | type
|:-| :--------  | :--------  | :--------
|  |--          |--          |--

<rem025 />

```ts 
import { seed } from "drizzle-seed";

await seed(db, schema, { count: 1000 }).refine((funcs) => ({
  posts: {
    columns: {
      id: funcs.intPrimaryKey(),
    },
  },
}));

```

### `number`

<rem025 />
Generates numbers with a floating point within the given range

|  | param      | default                                                                                               | type
|:-| :--------  | :--------                                                                                             | :--------
|  |`isUnique`  |`database column uniqueness`                                                                           |`boolean`
|  |`precision` |`100`                                                                                                  |`number`
|  |`maxValue`  |``` `precision * 1000` if isUnique equals false``` ``` `precision * count` if isUnique equals true```  |`number`
|  |`minValue`  |`-maxValue`                                                                                            |`number`
|  |`arraySize` |--                                                                                                     |`number`

<rem025 />
```ts 
import { seed } from "drizzle-seed";

await seed(db, schema, { count: 1000 }).refine((funcs) => ({
  products: {
    columns: {
      unitPrice: funcs.number({
        // lower border of range.
        minValue: 10,

        // upper border of range.
        maxValue: 120,
        
        // precision of generated number:
        // precision equals 10 means that values will be accurate to one tenth (1.2, 34.6);
        // precision equals 100 means that values will be accurate to one hundredth (1.23, 34.67).
        precision: 100,

        // property that controls if generated values gonna be unique or not.
        isUnique: false,

        // number of elements in each one-dimensional array. 
        // (If specified, arrays will be generated.)
        arraySize: 3
      }),
    },
  },
}));

```

### `int`

<rem025 />
Generates integers within the given range

|  | param      | default                                                                            | type
|:-| :--------  | :--------                                                                          | :--------
|  |`isUnique`  |`database column uniqueness`                                                        |`boolean`
|  |`maxValue`  |``` `1000` if isUnique equals false``` ``` `count * 10` if isUnique equals true```  |`number \| bigint`
|  |`minValue`  |`-maxValue`                                                                         |`number \| bigint`
|  |`arraySize` |--                                                                                  |`number`

<rem025 />
```ts 
import { seed } from "drizzle-seed";

await seed(db, schema, { count: 1000 }).refine((funcs) => ({
  products: {
    columns: {
      unitsInStock: funcs.int({
        // lower border of range.
        minValue: 0,

        // lower border of range.
        maxValue: 100,

        // property that controls if generated values gonna be unique or not.
        isUnique: false,

        // number of elements in each one-dimensional array. 
        // (If specified, arrays will be generated.)
        arraySize: 3
      }),
    },
  },
}));

```

### `boolean`

<rem025 />
Generates boolean values (true or false)

|  | param      | default    | type
|:-| :--------  | :--------  | :--------
|  |`arraySize` |--          |`number`

<rem025 />
```ts 
import { seed } from "drizzle-seed";

await seed(db, schema, { count: 1000 }).refine((funcs) => ({
  users: {
    columns: {
      isAvailable: funcs.boolean({
        // number of elements in each one-dimensional array. 
        // (If specified, arrays will be generated.)
        arraySize: 3
      }),
    },
  },
}));

```

### `date`

<rem025 />
Generates a date within the given range

|  | param      | default                                                                                                   | type
|:-| :--------  | :--------------                                                                                           | :--------
|  |`minDate`   |``` `'2024-05-08' - 4 years` - if maxDate is not set``` ``` `maxDate - 8 years`  - if maxDate is set ```   |`string \| Date`
|  |`maxDate`   |``` `'2024-05-08' + 4 years` - if minDate is not set``` ``` `minDate + 8 years`  - if minDate is set ```   |`string \| Date`
|  |`arraySize` |--                                                                                                         |`number`

<Callout type='warning'>
If only one of the parameters (`minDate` or `maxDate`) is provided, the unspecified parameter will be calculated by adding or subtracting 8 years to/from the specified one
</Callout>

<rem025 />
```ts 
import { seed } from "drizzle-seed";

await seed(db, schema, { count: 1000 }).refine((funcs) => ({
  users: {
    columns: {
      birthDate: funcs.date({
        // lower border of range.
        minDate: "1990-01-01",

        // upper border of range.
        maxDate: "2010-12-31",

        // number of elements in each one-dimensional array. 
        // (If specified, arrays will be generated.)
        arraySize: 3
      }),
    },
  },
}));

```

### `time`

<rem025 />
Generates time in 24-hour format

|  | param      | default             | type
|:-| :--------  | :--------           | :--------
|  |`min`       |`'00:00:00.000Z'`    |`string \| Date`
|  |`max`       |`'23:59:59.999Z'`    |`string \| Date`
|  |`arraySize` |--                   |`number`

<rem025 />
```ts 
import { seed } from "drizzle-seed";

await seed(db, schema, { count: 1000 }).refine((funcs) => ({
  users: {
    columns: {
      birthTime: funcs.time({
        // lower border of range.
        min: "11:12:13.141",

        // upper border of range.
        max: "15:16:17.181",

        // number of elements in each one-dimensional array. 
        // (If specified, arrays will be generated.)
        arraySize: 3
      }),
    },
  },
}));

```

### `timestamp`

<rem025 />
Generates timestamps

|  | param           | default                                                                                       | type
|:-| :--------       | :--------                                                                                     | :--------
|  |`min`            |``` `'2024-05-08' - 2 years` - if max is not set``` ``` `max - 4 years`  - if max is set ```   |`string \| Date`
|  |`max`            |``` `'2024-05-08' + 2 years` - if min is not set``` ``` `min + 4 years`  - if min is set ```   |`string \| Date`
|  |`arraySize`      |--                                                                                             |`number`

<rem025 />
```ts 
import { seed } from "drizzle-seed";

await seed(db, schema, { count: 1000 }).refine((funcs) => ({
  orders: {
    columns: {
      shippedDate: funcs.timestamp({
        // lower border of range.
        min: "2025-03-07T11:12:13.141",

        // upper border of range.
        max: "2025-03-08T15:16:17.181",

        // number of elements in each one-dimensional array. 
        // (If specified, arrays will be generated.)
        arraySize: 3
      }),
    },
  },
}));

```

### `datetime`

<rem025 />
Generates datetime objects

|  | param        | default                                                                                       | type
|:-| :--------    | :--------                                                                                     | :--------
|  |`min`         |``` `'2024-05-08' - 2 years` - if max is not set``` ``` `max - 4 years`  - if max is set ```   |`string \| Date`
|  |`max`         |``` `'2024-05-08' + 2 years` - if min is not set``` ``` `min + 4 years`  - if min is set ```   |`string \| Date`
|  |`arraySize`   |--                                                                                             |`number`
<rem025 />
```ts 
import { seed } from "drizzle-seed";

await seed(db, schema, { count: 1000 }).refine((funcs) => ({
  orders: {
    columns: {
      shippedDate: funcs.datetime({
        // lower border of range.
        min: "2025-03-07 13:12:13Z",
        
        // upper border of range.
        max: "2025-03-09 15:12:13Z",

        // number of elements in each one-dimensional array. 
        // (If specified, arrays will be generated.)
        arraySize: 3
      }),
    },
  },
}));

```

### `year`

<rem025 />
Generates years in `YYYY` format

|  | param      | default    | type
|:-| :--------  | :--------  | :--------
|  |`arraySize` |--          |`number`

<rem025 />
```ts 
import { seed } from "drizzle-seed";

await seed(db, schema, { count: 1000 }).refine((funcs) => ({
  users: {
    columns: {
      birthYear: funcs.year({
        // number of elements in each one-dimensional array. 
        // (If specified, arrays will be generated.)
        arraySize: 3
      }),
    },
  },
}));

```

### `json`

<rem025 />
Generates JSON objects with a fixed structure

```ts
{ email, name, isGraduated, hasJob, salary, startedWorking, visitedCountries}

// or

{ email, name, isGraduated, hasJob, visitedCountries }
```

> The JSON structure will be picked randomly

|  | param      | default    | type
|:-| :--------  | :--------  | :--------
|  |`arraySize` |--          |`number`

<rem025 />
```ts 
import { seed } from "drizzle-seed";

await seed(db, schema, { count: 1000 }).refine((funcs) => ({
  users: {
    columns: {
      metadata: funcs.json({
        // number of elements in each one-dimensional array. 
        // (If specified, arrays will be generated.)
        arraySize: 3
      }),
    },
  },
}));

```

### `interval`

<rem025 />
Generates time intervals.

Example of a generated value: `1 year 12 days 5 minutes`

|  | param      | default                     | type
|:-| :--------  | :--------                   | :--------
|  |`isUnique`  |`database column uniqueness` |`boolean`
|  |`arraySize` |--                           |`number`

<rem025 />
```ts 
import { seed } from "drizzle-seed";

await seed(db, schema, { count: 1000 }).refine((funcs) => ({
  users: {
    columns: {
      timeSpentOnWebsite: funcs.interval({
        // `isUnique` - property that controls whether the generated values will be unique or not
        isUnique: true,

        // number of elements in each one-dimensional array. 
        // (If specified, arrays will be generated.)
        arraySize: 3
      }),
    },
  },
}));

```

### `string`

<rem025 />
Generates random strings

|  | param      | default                     | type
|:-| :--------  | :--------                   | :--------
|  |`isUnique`  |`database column uniqueness` |`boolean`
|  |`arraySize` |--                           |`number`

<rem025 />
```ts 
import { seed } from "drizzle-seed";

await seed(db, schema, { count: 1000 }).refine((funcs) => ({
  users: {
    columns: {
      hashedPassword: funcs.string({
        // `isUnique` - property that controls whether the generated values will be unique or not
        isUnique: false,
        
        // number of elements in each one-dimensional array. 
        // (If specified, arrays will be generated.)
        arraySize: 3
      }),
    },
  },
}));

```

### `uuid`

<rem025 />
Generates v4 UUID strings

|  | param      | default    | type
|:-| :--------  | :--------  | :--------
|  |`arraySize` |--          |`number`

<rem025 />
```ts 
import { seed } from "drizzle-seed";
await seed(db, schema, { count: 1000 }).refine((funcs) => ({
  products: {
    columns: {
      id: funcs.uuid({
        // number of elements in each one-dimensional array. 
        // (If specified, arrays will be generated.)
        arraySize: 3
      }),
    },
  },
}));
```

### `firstName`

<rem025 />
Generates a person's first name

|  | param      | default                     | type
|:-| :--------  | :--------                   | :--------
|  |`isUnique`  |`database column uniqueness` |`boolean`
|  |`arraySize` |--                           |`number`

<rem025 />
```ts 
import { seed } from "drizzle-seed";

await seed(db, schema, { count: 1000 }).refine((funcs) => ({
  users: {
    columns: {
      firstName: funcs.firstName({
        // `isUnique` - property that controls whether the generated values will be unique or not
        isUnique: true,

        // number of elements in each one-dimensional array. 
        // (If specified, arrays will be generated.)
        arraySize: 3
      }),
    },
  },
}));

```

### `lastName`

<rem025 />
Generates a person's last name

|  | param      | default                     | type
|:-| :--------  | :--------                   | :--------
|  |`isUnique`  |`database column uniqueness` |`boolean`
|  |`arraySize` |--                           |`number`

<rem025 />
```ts 
import { seed } from "drizzle-seed";

await seed(db, schema, { count: 1000 }).refine((funcs) => ({
  users: {
    columns: {
      lastName: funcs.lastName({
        // `isUnique` - property that controls whether the generated values will be unique or not
        isUnique: false,
        
        // number of elements in each one-dimensional array. 
        // (If specified, arrays will be generated.)
        arraySize: 3
      }),
    },
  },
}));

```

### `fullName`

<rem025 />
Generates a person's full name

|  | param      | default                     | type
|:-| :--------  | :--------                   | :--------
|  |`isUnique`  |`database column uniqueness` |`boolean`
|  |`arraySize` |--                           |`number`

<rem025 />
```ts 
import { seed } from "drizzle-seed";

await seed(db, schema, { count: 1000 }).refine((funcs) => ({
  users: {
    columns: {
      fullName: funcs.fullName({
        // `isUnique` - property that controls whether the generated values will be unique or not
        isUnique: true,

        // number of elements in each one-dimensional array. 
        // (If specified, arrays will be generated.)
        arraySize: 3
      }),
    },
  },
}));

```

### `email`

<rem025 />
Generates unique email addresses

|  | param      | default    | type
|:-| :--------  | :--------  | :--------
|  |`arraySize` |--          |`number`

<rem025 />
```ts 
import { seed } from "drizzle-seed";

await seed(db, schema, { count: 1000 }).refine((funcs) => ({
  users: {
    columns: {
      email: funcs.email({
        // number of elements in each one-dimensional array. 
        // (If specified, arrays will be generated.)
        arraySize: 3
      }),
    },
  },
}));

```

### `phoneNumber`

<rem025 />
Generates unique phone numbers

|  | param                    | default                                         | type
|:-| :--------                | :--------                                       | :--------
|  |`template`                |--                                               |`string`
|  |`prefixes`                |[Used dataset for prefixes](https://github.com/OleksiiKH0240/drizzle-orm/blob/main/drizzle-seed/src/datasets/phonesInfo.ts)   |`string[]`
|  |`generatedDigitsNumbers`  | `7` - `if prefixes was defined`                 |`number \| number[]`
|  |`arraySize`               |--                                               |`number`

<rem025 />
```ts 
import { seed } from "drizzle-seed";

//generate phone number using template property
await seed(db, schema, { count: 1000 }).refine((funcs) => ({
  users: {
    columns: {
      phoneNumber: funcs.phoneNumber({ 
        // `template` - phone number template, where all '#' symbols will be substituted with generated digits.
        template: "+(380) ###-####",

        // number of elements in each one-dimensional array. 
        // (If specified, arrays will be generated.)
        arraySize: 3
      }),
    },
  },
}));

```
```ts 
import { seed } from "drizzle-seed";

//generate phone number using prefixes and generatedDigitsNumbers properties
await seed(db, schema, { count: 1000 }).refine((funcs) => ({
  users: {
    columns: {
      phoneNumber: funcs.phoneNumber({
        // `prefixes` - array of any string you want to be your phone number prefixes.(not compatible with `template` property)
        prefixes: ["+380 99", "+380 67"],

        // `generatedDigitsNumbers` - number of digits that will be added at the end of prefixes.(not compatible with `template` property)
        generatedDigitsNumbers: 7,

        // number of elements in each one-dimensional array. 
        // (If specified, arrays will be generated.)
        arraySize: 3
      }),
    },
  },
}));

```
```ts 
import { seed } from "drizzle-seed";

// generate phone number using prefixes and generatedDigitsNumbers properties but with different generatedDigitsNumbers for prefixes
await seed(db, schema, { count: 1000 }).refine((funcs) => ({
  users: {
    columns: {
      phoneNumber: funcs.phoneNumber({
        // `prefixes` - array of any string you want to be your phone number prefixes.(not compatible with `template` property)
        prefixes: ["+380 99", "+380 67", "+1"],

        // `generatedDigitsNumbers` - number of digits that will be added at the end of prefixes.(not compatible with `template` property)
        generatedDigitsNumbers: [7, 7, 10],

        // number of elements in each one-dimensional array. 
        // (If specified, arrays will be generated.)
        arraySize: 3
      }),
    },
  },
}));

```
### `country`

<rem025 />
Generates country's names

|  | param      | default                     | type
|:-| :--------  | :--------                   | :--------
|  |`isUnique`  |`database column uniqueness` |`boolean`
|  |`arraySize` |--                           |`number`

<rem025 />

```ts 
import { seed } from "drizzle-seed";

await seed(db, schema, { count: 1000 }).refine((funcs) => ({
  users: {
    columns: {
      country: funcs.country({
        // `isUnique` - property that controls whether the generated values will be unique or not
        isUnique: false,
        
        // number of elements in each one-dimensional array. 
        // (If specified, arrays will be generated.)
        arraySize: 3
      }),
    },
  },
}));

```

### `city`

<rem025 />
Generates city's names

|  | param      | default                     | type
|:-| :--------  | :--------                   | :--------
|  |`isUnique`  |`database column uniqueness` |`boolean`
|  |`arraySize` |--                           |`number`

<rem025 />

```ts 
import { seed } from "drizzle-seed";

await seed(db, schema, { count: 1000 }).refine((funcs) => ({
  users: {
    columns: {
      city: funcs.city({
        // `isUnique` - property that controls whether the generated values will be unique or not
        isUnique: false,

        // number of elements in each one-dimensional array. 
        // (If specified, arrays will be generated.)
        arraySize: 3
      }),
    },
  },
}));

```

### `streetAddress`

<rem025 />
Generates street address

|  | param      | default                     | type
|:-| :--------  | :--------                   | :--------
|  |`isUnique`  |`database column uniqueness` |`boolean`
|  |`arraySize` |--                           |`number`

<rem025 />

```ts 
import { seed } from "drizzle-seed";

await seed(db, schema, { count: 1000 }).refine((funcs) => ({
  users: {
    columns: {
      streetAddress: funcs.streetAddress({
        // `isUnique` - property that controls whether the generated values will be unique or not
        isUnique: false,
        
        // number of elements in each one-dimensional array. 
        // (If specified, arrays will be generated.)
        arraySize: 3 
      }),
    },
  },
}));

```

### `jobTitle`

<rem025 />
Generates job titles

|  | param      | default    | type
|:-| :--------  | :--------  | :--------
|  |`arraySize` |--          |`number`

<rem025 />

```ts 
import { seed } from "drizzle-seed";

await seed(db, schema, { count: 1000 }).refine((funcs) => ({
  users: {
    columns: {
      jobTitle: funcs.jobTitle({
        // number of elements in each one-dimensional array. 
        // (If specified, arrays will be generated.)
        arraySize: 3
      }),
    },
  },
}));

```

### `postcode`

<rem025 />
Generates postal codes

|  | param      | default                     | type
|:-| :--------  | :--------                   | :--------
|  |`isUnique`  |`database column uniqueness` |`boolean`
|  |`arraySize` |--                           |`number`

<rem025 />

```ts 
import { seed } from "drizzle-seed";

await seed(db, schema, { count: 1000 }).refine((funcs) => ({
  users: {
    columns: {
      postcode: funcs.postcode({
        // `isUnique` - property that controls whether the generated values will be unique or not
        isUnique: true,

        // number of elements in each one-dimensional array. 
        // (If specified, arrays will be generated.)
        arraySize: 3
      }),
    },
  },
}));

```

### `state`

<rem025 />
Generates US states

|  | param      | default    | type
|:-| :--------  | :--------  | :--------
|  |`arraySize` |--          |`number`

<rem025 />

```ts 
import { seed } from "drizzle-seed";

await seed(db, schema, { count: 1000 }).refine((funcs) => ({
  users: {
    columns: {
      state: funcs.state({
        // number of elements in each one-dimensional array. 
        // (If specified, arrays will be generated.)
        arraySize: 3
      }),
    },
  },
}));

```

### `companyName`

<rem025 />
Generates random company's names

|  | param      | default                     | type
|:-| :--------  | :--------                   | :--------
|  |`isUnique`  |`database column uniqueness` |`boolean`
|  |`arraySize` |--                           |`number`

<rem025 />

```ts 
import { seed } from "drizzle-seed";

await seed(db, schema, { count: 1000 }).refine((funcs) => ({
  users: {
    columns: {
      company: funcs.companyName({ 
        // `isUnique` - property that controls whether the generated values will be unique or not
        isUnique: true,

        // number of elements in each one-dimensional array. 
        // (If specified, arrays will be generated.)
        arraySize: 3
      }),
    },
  },
}));

```
### `loremIpsum`

<rem025 />
Generates `lorem ipsum` text sentences.

|  | param            | default    | type
|:-| :--------        | :--------  | :--------
|  |`sentencesCount`  | 1          |`number`
|  |`arraySize`       |--          |`number`

<rem025 />

```ts 
import { seed } from "drizzle-seed";

await seed(db, schema, { count: 1000 }).refine((funcs) => ({
  posts: {
    columns: {
      content: funcs.loremIpsum({
        // `sentencesCount` - number of sentences you want to generate as one generated value(string).
        sentencesCount: 2,

        // number of elements in each one-dimensional array. 
        // (If specified, arrays will be generated.)
        arraySize: 3
      }),
    },
  },
}));

```

### `point`

<rem025 />
Generates 2D points within specified ranges for x and y coordinates.

|  | param       | default                                                                                 | type
|:-| :--------   | :--------                                                                               | :--------
|  |`isUnique`   |`database column uniqueness`                                                             |`boolean`
|  |`maxXValue`  |``` `10 * 1000` if isUnique equals false``` ``` `10 * count` if isUnique equals true```  |`number`
|  |`minXValue`  |`-maxXValue`                                                                             |`number`
|  |`maxYValue`  |``` `10 * 1000` if isUnique equals false``` ``` `10 * count` if isUnique equals true```  |`number`
|  |`minYValue`  |`-maxYValue`                                                                             |`number`
|  |`arraySize`  |--                                                                                       |`number`


<rem025 />

```ts 
import { seed } from "drizzle-seed";

await seed(db, schema, { count: 1000 }).refine((funcs) => ({
  triangles: {
    columns: {
      pointCoords: funcs.point({
        // `isUnique` - property that controls if generated values gonna be unique or not.
        isUnique: true,

        // `minXValue` - lower bound of range for x coordinate.
        minXValue: -5,

        // `maxXValue` - upper bound of range for x coordinate.
        maxXValue: 20,

        // `minYValue` - lower bound of range for y coordinate.
        minYValue: 0,

        // `maxYValue` - upper bound of range for y coordinate.
        maxYValue: 30,

        // number of elements in each one-dimensional array. 
        // (If specified, arrays will be generated.)
        arraySize: 3
      }),
    },
  },
}));

```

### `line`

<rem025 />
Generates 2D lines within specified ranges for a, b and c parameters of line.

```
line equation: a*x + b*y + c = 0
```

|  | param       | default                                                                                 | type
|:-| :--------   | :--------                                                                               | :--------
|  |`isUnique`   |`database column uniqueness`                                                             |`boolean`
|  |`maxAValue`  |``` `10 * 1000` if isUnique equals false``` ``` `10 * count` if isUnique equals true```  |`number`
|  |`minAValue`  |`-maxAValue`                                                                             |`number`
|  |`maxBValue`  |``` `10 * 1000` if isUnique equals false``` ``` `10 * count` if isUnique equals true```  |`number`
|  |`minBValue`  |`-maxBValue`                                                                             |`number`
|  |`maxCValue`  |``` `10 * 1000` if isUnique equals false``` ``` `10 * count` if isUnique equals true```  |`number`
|  |`minCValue`  |`-maxCValue`                                                                             |`number`
|  |`arraySize`  |--                                                                                       |`number`
<rem025 />

```ts 
import { seed } from "drizzle-seed";

await seed(db, schema, { count: 1000 }).refine((funcs) => ({
  lines: {
    columns: {
      lineParams: funcs.point({
        // `isUnique` - property that controls if generated values gonna be unique or not.
        isUnique: true,

        // `minAValue` - lower bound of range for a parameter.
        minAValue: -5,

        // `maxAValue` - upper bound of range for x parameter.
        maxAValue: 20,

        // `minBValue` - lower bound of range for y parameter.
        minBValue: 0,

        // `maxBValue` - upper bound of range for y parameter.
        maxBValue: 30,

        // `minCValue` - lower bound of range for y parameter.
        minCValue: 0,

        // `maxCValue` - upper bound of range for y parameter.
        maxCValue: 10,

        // number of elements in each one-dimensional array. 
        // (If specified, arrays will be generated.)
        arraySize: 3
      }),
    },
  },
}));

```

### `bitString`

<rem025 />
Generates bit strings based on specified parameters.

|  | param       | default                                                                                 | type
|:-| :--------   | :--------                                                                               | :--------
|  |`isUnique`   |`database column uniqueness`                                                             |`boolean`
|  |`dimensions` |`database column bit-length`                                                             |`number`
|  |`arraySize`  |--                                                                                       |`number`
<rem025 />

```ts 
import { seed } from "drizzle-seed";

await seed(db, schema, { count: 1000 }).refine((funcs) => ({
  bitStringTable: {
    columns: {
      bit: funcs.bitString({
        // desired length of each bit string (e.g., `dimensions = 3` produces values like `'010'`).
        dimensions: 12,

        // property that controls if generated values gonna be unique or not;
        isUnique: true,

        // number of elements in each one-dimensional array (If specified, arrays will be generated);
        arraySize: 3,
      }),
    },
  },
}));

```

### `inet`

<rem025 />
Generates ip addresses based on specified parameters.

|  | param       | default                                                                                 | type
|:-| :--------   | :--------                                                                               | :--------
|  |`isUnique`   |`database column uniqueness`                                                             |`boolean`
|  |`arraySize`  |--                                                                                       |`number`
|  |`ipAddress`  |`'ipv4'`                                                                                 |`'ipv4' \| 'ipv6'`
|  |`includeCidr`|`true`                                                                                   |`boolean`
<rem025 />

```ts 
import { seed } from "drizzle-seed";

await seed(db, schema, { count: 1000 }).refine((funcs) => ({
  inetTable: {
    columns: {
      inet: funcs.inet({
        // property that controls if generated values gonna be unique or not;
        isUnique: true,

        // number of elements in each one-dimensional array (If specified, arrays will be generated);
        arraySize: 3,

        // type of IP address to generate — either "ipv4" or "ipv6";
        ipAddress: "ipv4",

        // determines whether generated IPs include a CIDR suffix.
        includeCidr: true,
      }),
    },
  },
}));
```

### `geometry`

<rem025 />
Generates geometry objects based on the given parameters.

<Callout title='warnings'>
<Tabs items={['arraySize', 'srid']}>
<Tab>
Currently, if you set arraySize to a value greater than 1 
or try to insert more than one `geometry point` element into a `geometry(point, 0)[]` column in CockroachDB or CockroachDB via drizzle-orm, 
you’ll encounter an error.

This bug is already in the backlog.

<Callout title="❌">
```ts {13}
import { seed } from "drizzle-seed";
import { geometry, cockroachTable } from 'drizzle-orm/cockroach-core';

const geometryTable = cockroachTable('geometry_table', {
	geometryArray: geometry('geometry_array', { type: 'point', srid: 0 }).array(3),
});

await seed(db, { geometryTable }, { count: 1000 }).refine((funcs) => ({
  geometryTable: {
    columns: {
      geometryArray: funcs.geometry({
        // currently arraySize with values > 1 are not supported
        arraySize: 3,
      }),
    },
  },
}));
```
</Callout>

<Callout title='✅'>
```ts {13}
import { seed } from "drizzle-seed";
import { geometry, cockroachTable } from 'drizzle-orm/cockroach-core';

const geometryTable = cockroachTable('geometry_table', {
	geometryArray: geometry('geometry_array', { type: 'point', srid: 0 }).array(1),
});

await seed(db, { geometryTable }, { count: 1000 }).refine((funcs) => ({
  geometryTable: {
    columns: {
      geometryArray: funcs.geometry({
        // will work as expected
        arraySize: 1,
      }),
    },
  },
}));
```
</Callout>
</Tab>

<Tab>
Currently, if you set the SRID of a `geometry(point)` column to anything other than 0 (for example, 4326) in your drizzle-orm table declaration, 
you’ll encounter an error during the seeding process.

This bug is already in the backlog.

<Callout title="❌">
```ts {5}
import { seed } from "drizzle-seed";
import { geometry, cockroachTable } from 'drizzle-orm/cockroach-core';

const geometryTable = cockroachTable('geometry_table', {
	geometryColumn: geometry('geometry_column', { type: 'point', srid: 4326 }),
});

await seed(db, { geometryTable }, { count: 1000 }).refine((funcs) => ({
  geometryTable: {
    columns: {
      geometryColumn: funcs.geometry({
        srid: 4326,
      }),
    },
  },
}));
```
</Callout>

<Callout title='✅'>
```ts {5}
import { seed } from "drizzle-seed";
import { geometry, cockroachTable } from 'drizzle-orm/cockroach-core';

const geometryTable = cockroachTable('geometry_table', {
	geometryColumn: geometry('geometry_column', { type: 'point', srid: 0 }),
});

await seed(db, { geometryTable }, { count: 1000 }).refine((funcs) => ({
  geometryTable: {
    columns: {
      geometryColumn: funcs.geometry({
        srid: 4326,
      }),
    },
  },
}));
```
</Callout>
</Tab>
</Tabs>
</Callout>

|  | param          | default                                                                                 | type
|:-| :--------      | :--------                                                                               | :--------
|  |`isUnique`      |`database column uniqueness`                                                             |`boolean`
|  |`arraySize`     |--                                                                                       |`number`
|  |`type`          |`'point'`                                                                                |`'point'`
|  |`srid`          |`4326`                                                                                   |`4326 \| 3857`
|  |`decimalPlaces` |`6`                                                                                      |`1 \| 2 \| 3 \| 4 \| 5 \| 6 \| 7`
<rem025 />

```ts 
import { seed } from "drizzle-seed";

await seed(db, schema, { count: 1000 }).refine((funcs) => ({
  geometryTable: {
    columns: {
      geometryPointTuple: funcs.geometry({
        // property that controls if generated values gonna be unique or not;
        isUnique: true,

        // number of elements in each one-dimensional array (If specified, arrays will be generated);
        arraySize: 1,

        // geometry type to generate; currently only `'point'` is supported;
        type: "point",

        // Spatial Reference System Identifier: determines what type of point will be generated - either `4326` or `3857`;
        srid: 4326,

        // number of decimal places for points when `srid` is `4326` (e.g., `decimalPlaces = 3` produces values like `'point(30.723 46.482)'`).
        decimalPlaces: 5,
      }),
    },
  },
}));

```

### `vector`

<rem025 />
Generates vectors based on the provided parameters.

|  | param          | default                                                      | type
|:-| :--------      | :--------                                                    | :--------
|  |`isUnique`      |`database column uniqueness`                                  |`boolean`
|  |`arraySize`     |--                                                            |`number`
|  |`decimalPlaces` |`2`                                                           |`number`
|  |`dimensions`    |`database column’s dimensions`                                |`number`
|  |`minValue`      |`-1000`                                                       |`number`
|  |`maxValue`      |`1000`                                                        |`number`
<rem025 />

```ts 
import { seed } from "drizzle-seed";

await seed(db, schema, { count: 1000 }).refine((funcs) => ({
  vectorTable: {
    columns: {
      vector: funcs.vector({
        // property that controls if generated values gonna be unique or not;
        isUnique: true,

        // number of elements in each one-dimensional array (If specified, arrays will be generated);
        arraySize: 3,

        // number of decimal places for each vector element (e.g., `decimalPlaces = 3` produces values like `1.123`);
        decimalPlaces: 5,

        // number of elements in each generated vector (e.g., `dimensions = 3` produces values like `[1,2,3]`);
        dimensions: 12,

        // minimum allowed value for each vector element;
        minValue: -100,

        // maximum allowed value for each vector element.
        maxValue: 100,
      }),
    },
  },
}));

```

Source: https://orm.drizzle.team/docs/cockroach/seed-overview

import Npm from "@mdx/Npm.astro";
import Callout from '@mdx/Callout.astro';
import CodeTabs from "@mdx/CodeTabs.astro";
import Section from "@mdx/Section.astro";

# Drizzle Seed

`drizzle-seed` is a TypeScript library that helps you generate deterministic, yet realistic,
fake data to populate your database. By leveraging a seedable pseudorandom number generator (pRNG),
it ensures that the data you generate is consistent and reproducible across different runs.
This is especially useful for testing, development, and debugging purposes.

#### What is Deterministic Data Generation?

Deterministic data generation means that the same input will always produce the same output.
In the context of `drizzle-seed`, when you initialize the library with the same seed number,
it will generate the same sequence of fake data every time. This allows for predictable and repeatable data sets.

#### Pseudorandom Number Generator (pRNG)

A pseudorandom number generator is an algorithm that produces a sequence of numbers
that approximates the properties of random numbers. However, because it's based on an initial value
called a seed, you can control its randomness. By using the same seed, the pRNG will produce the
same sequence of numbers, making your data generation process reproducible.

#### Benefits of Using a pRNG:

- Consistency: Ensures that your tests run on the same data every time.
- Debugging: Makes it easier to reproduce and fix bugs by providing a consistent data set.
- Collaboration: Team members can share seed numbers to work with the same data sets.

With drizzle-seed, you get the best of both worlds: the ability to generate realistic fake data and the control to reproduce it whenever needed.

## Installation

<Npm>drizzle-seed</Npm>

## Basic Usage

In this example we will create 10 users with random names and ids

```ts {12}
import { cockroachTable, int4, text } from "drizzle-orm/cockroach-core";
import { drizzle } from "drizzle-orm/cockroach";
import { seed } from "drizzle-seed";

const users = cockroachTable("users", {
  id: int4().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

```ts
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

```ts
await seed(db, schema, { seed: 12345 });
```

## Reset database

With `drizzle-seed`, you can easily reset your database and seed it with new values, for example, in your test suites

```ts
// path to a file with schema you want to reset
import * as schema from "./schema.ts";
import { reset } from "drizzle-seed";

async function main() {
  const db = drizzle(process.env.DATABASE_URL!);
  await reset(db, schema);
}

main();
```

Different dialects will have different strategies for database resetting

For CockroachDB, the `drizzle-seed` package will generate `TRUNCATE` statements with the `CASCADE` option to 
ensure that all tables are empty after running the reset function

```sql
TRUNCATE tableName1, tableName2, ... CASCADE;
```

## Refinements

In case you need to change the behavior of the seed generator functions that `drizzle-seed` uses by default, you can specify your own implementation and even use your own list of values for the seeding process

`.refine` is a callback that receives a list of all available generator functions from `drizzle-seed`. It should return an object with keys representing the tables you want to refine, defining their behavior as needed. 
Each table can specify several properties to simplify seeding your database:

<rem025 />

- `columns`: Refine the default behavior of each column by specifying the required generator function, or exclude the column from seeding by specifying `false`.
- `count`: Specify the number of rows to insert into the database. By default, it's 10. If a global count is defined in the `seed()` options, the count defined here will override it for this specific table.
- `with`: Define how many referenced entities to create for each parent table if you want to generate associated entities.

<Callout title='info'>
You can also specify a weighted random distribution for the number of referenced values you want to create. For details on this API, you can refer to [Weighted Random docs](#weighted-random) docs section
</Callout>

**API**
```ts
await seed(db, schema).refine((f) => ({
  users: {
    columns: {},
    count: 10,
    with: {
        posts: 10
    }
  },
}));
```

Let's check a few examples with an explanation of what will happen:

```ts filename='schema.ts'
import { cockroachTable, int4, text } from "drizzle-orm/cockroach-core";

export const users = cockroachTable("users", {
  id: int4().primaryKey(),
  name: text().notNull(),
});

export const posts = cockroachTable("posts", {
  id: int4().primaryKey(),
  description: text(),
  userId: int4().references(() => users.id),
});
```

**Example 1**: Seed only the `users` table with 20 entities and with refined seed logic for the `name` column
```ts filename='index.ts'
import { drizzle } from "drizzle-orm/cockroach";
import { seed } from "drizzle-seed";
import * as schema from './schema.ts'

async function main() {
  const db = drizzle(process.env.DATABASE_URL!);

  await seed(db, { users: schema.users }).refine((f) => ({
    users: {
        columns: {
            name: f.fullName(),
        },
        count: 20
    }
  }));
}

main();
```

**Example 2**: Seed only the `users` table, excluding the `name` column from seeding
```ts filename='index.ts'
import { drizzle } from "drizzle-orm/cockroach";
import { seed } from "drizzle-seed";
import * as schema from './schema.ts'

async function main() {
  const db = drizzle(process.env.DATABASE_URL!);

  await seed(db, { users: schema.users }).refine((f) => ({
    users: {
        columns: {
            name: false, // the name column will not be seeded, allowing the database to use its default value.
        }
    }
  }));
}

main();
```

**Example 3**: Seed the `users` table with 20 entities and add 10 `posts` for each `user` by seeding the `posts` table and creating a reference from `posts` to `users`
```ts filename='index.ts'
import { drizzle } from "drizzle-orm/cockroach";
import { seed } from "drizzle-seed";
import * as schema from './schema.ts'

async function main() {
  const db = drizzle(process.env.DATABASE_URL!);

  await seed(db, schema).refine((f) => ({
    users: {
        count: 20,
        with: {
            posts: 10
        }
    }
  }));
}

main();
```

**Example 4**: Seed the `users` table with 5 entities and populate the database with 100 `posts` without connecting them to the `users` entities. Refine `id` generation for `users` so 
that it will give any int from `10000` to `20000` and remains unique, and refine `posts` to retrieve values from a self-defined array
```ts filename='index.ts'
import { drizzle } from "drizzle-orm/cockroach";
import { seed } from "drizzle-seed";
import * as schema from './schema.ts'

async function main() {
  const db = drizzle(process.env.DATABASE_URL!);

  await seed(db, schema).refine((f) => ({
    users: {
        count: 5,
        columns: {
            id: f.int({
              minValue: 10000,
              maxValue: 20000,
              isUnique: true,
            }),
        }
    },
    posts: {
        count: 100,
        columns: {
            description: f.valuesFromArray({
            values: [
                "The sun set behind the mountains, painting the sky in hues of orange and purple", 
                "I can't believe how good this homemade pizza turned out!", 
                "Sometimes, all you need is a good book and a quiet corner.", 
                "Who else thinks rainy days are perfect for binge-watching old movies?", 
                "Tried a new hiking trail today and found the most amazing waterfall!",
                // ...
            ],
          })
        }
    }
  }));
}

main();
```

<Callout type='warning'>
There are many more possibilities that we will define in these docs, but for now, you can explore a few sections in this documentation. Check the [Generators](/docs/cockroach/seed-functions) section to get familiar with all the available generator functions you can use.

A particularly great feature is the ability to use weighted randomization, both for generator values created for a column and for determining the number of related entities that can be generated by `drizzle-seed`.

Please check [Weighted Random docs](#weighted-random) for more info.
</Callout>

## Weighted Random

There may be cases where you need to use multiple datasets with a different priority that should be inserted into your database during the seed stage. For such cases, drizzle-seed provides an API called weighted random

The Drizzle Seed package has a few places where weighted random can be used:

- Columns inside each table refinements
- The `with` property, determining the amount of related entities to be created

Let's check an example for both:

```ts filename="schema.ts"
import { cockroachTable, int4, text, varchar, doublePrecision } from "drizzle-orm/cockroach-core";

export const orders = cockroachTable(
  "orders",
  {
    id: int4().primaryKey(),
    name: text().notNull(),
    quantityPerUnit: varchar().notNull(),
    unitPrice: doublePrecision().notNull(),
    unitsInStock: int4().notNull(),
    unitsOnOrder: int4().notNull(),
    reorderLevel: int4().notNull(),
    discontinued: int4().notNull(),
  }
);

export const details = cockroachTable(
  "details",
  {
    unitPrice: doublePrecision().notNull(),
    quantity: int4().notNull(),
    discount: doublePrecision().notNull(),

    orderId: int4()
      .notNull()
      .references(() => orders.id, { onDelete: "cascade" }),
  }
);
```

**Example 1**: Refine the `unitPrice` generation logic to generate `5000` random prices, with a 30% chance of prices between 10-100 and a 70% chance of prices between 100-300

```ts filename="index.ts"
import { drizzle } from "drizzle-orm/cockroach";
import { seed } from "drizzle-seed";
import * as schema from './schema.ts'

async function main() {
  const db = drizzle(process.env.DATABASE_URL!);

  await seed(db, schema).refine((f) => ({
    orders: {
       count: 5000,
       columns: {
           unitPrice: f.weightedRandom(
               [
                   {
                       weight: 0.3,
                       value: f.int({ minValue: 10, maxValue: 100 })
                   },
                   {
                       weight: 0.7,
                       value: f.number({ minValue: 100, maxValue: 300, precision: 100 })
                   }
               ]
           ),
       }
    }
  }));
}

main();
```

**Example 2**: For each order, generate 1 to 3 details with a 60% chance, 5 to 7 details with a 30% chance, and 8 to 10 details with a 10% chance

```ts filename="index.ts"
import { drizzle } from "drizzle-orm/cockroach";
import { seed } from "drizzle-seed";
import * as schema from './schema.ts'

async function main() {
  const db = drizzle(process.env.DATABASE_URL!);

  await seed(db, schema).refine((f) => ({
    orders: {
       with: {
           details:
               [
                   { weight: 0.6, count: [1, 2, 3] },
                   { weight: 0.3, count: [5, 6, 7] },
                   { weight: 0.1, count: [8, 9, 10] },
               ]
       }
    }
  }));
}

main();
```

## Complex example

<CodeTabs items={["main.ts", "schema.ts"]}>
<Section>
```ts
import { seed } from "drizzle-seed";
import * as schema from "./schema.ts";

const main = async () => {
    const titlesOfCourtesy = ["Ms.", "Mrs.", "Dr."];
    const unitsOnOrders = [0, 10, 20, 30, 50, 60, 70, 80, 100];
    const reorderLevels = [0, 5, 10, 15, 20, 25, 30];
    const quantityPerUnit = [
        "100 - 100 g pieces",
        "100 - 250 g bags",
        "10 - 200 g glasses",
        "10 - 4 oz boxes",
        "10 - 500 g pkgs.",
        "10 - 500 g pkgs."
    ];
    const discounts = [0.05, 0.15, 0.2, 0.25];

    await seed(db, schema).refine((funcs) => ({
        customers: {
            count: 10000,
            columns: {
                companyName: funcs.companyName(),
                contactName: funcs.fullName(),
                contactTitle: funcs.jobTitle(),
                address: funcs.streetAddress(),
                city: funcs.city(),
                postalCode: funcs.postcode(),
                region: funcs.state(),
                country: funcs.country(),
                phone: funcs.phoneNumber({ template: "(###) ###-####" }),
                fax: funcs.phoneNumber({ template: "(###) ###-####" })
            }
        },
        employees: {
            count: 200,
            columns: {
                firstName: funcs.firstName(),
                lastName: funcs.lastName(),
                title: funcs.jobTitle(),
                titleOfCourtesy: funcs.valuesFromArray({ values: titlesOfCourtesy }),
                birthDate: funcs.date({ minDate: "2010-12-31", maxDate: "2010-12-31" }),
                hireDate: funcs.date({ minDate: "2010-12-31", maxDate: "2024-08-26" }),
                address: funcs.streetAddress(),
                city: funcs.city(),
                postalCode: funcs.postcode(),
                country: funcs.country(),
                homePhone: funcs.phoneNumber({ template: "(###) ###-####" }),
                extension: funcs.int({ minValue: 428, maxValue: 5467 }),
                notes: funcs.loremIpsum()
            }
        },
        orders: {
            count: 50000,
            columns: {
                shipVia: funcs.int({ minValue: 1, maxValue: 3 }),
                freight: funcs.number({ minValue: 0, maxValue: 1000, precision: 100 }),
                shipName: funcs.streetAddress(),
                shipCity: funcs.city(),
                shipRegion: funcs.state(),
                shipPostalCode: funcs.postcode(),
                shipCountry: funcs.country()
            },
            with: {
                details:
                    [
                        { weight: 0.6, count: [1, 2, 3, 4] },
                        { weight: 0.2, count: [5, 6, 7, 8, 9, 10] },
                        { weight: 0.15, count: [11, 12, 13, 14, 15, 16, 17] },
                        { weight: 0.05, count: [18, 19, 20, 21, 22, 23, 24, 25] },
                    ]
            }
        },
        suppliers: {
            count: 1000,
            columns: {
                companyName: funcs.companyName(),
                contactName: funcs.fullName(),
                contactTitle: funcs.jobTitle(),
                address: funcs.streetAddress(),
                city: funcs.city(),
                postalCode: funcs.postcode(),
                region: funcs.state(),
                country: funcs.country(),
                phone: funcs.phoneNumber({ template: "(###) ###-####" })
            }
        },
        products: {
            count: 5000,
            columns: {
                name: funcs.companyName(),
                quantityPerUnit: funcs.valuesFromArray({ values: quantityPerUnit }),
                unitPrice: funcs.weightedRandom(
                    [
                        {
                            weight: 0.5,
                            value: funcs.int({ minValue: 3, maxValue: 300 })
                        },
                        {
                            weight: 0.5,
                            value: funcs.number({ minValue: 3, maxValue: 300, precision: 100 })
                        }
                    ]
                ),
                unitsInStock: funcs.int({ minValue: 0, maxValue: 125 }),
                unitsOnOrder: funcs.valuesFromArray({ values: unitsOnOrders }),
                reorderLevel: funcs.valuesFromArray({ values: reorderLevels }),
                discontinued: funcs.int({ minValue: 0, maxValue: 1 })
            }
        },
        details: {
            columns: {
                unitPrice: funcs.number({ minValue: 10, maxValue: 130 }),
                quantity: funcs.int({ minValue: 1, maxValue: 130 }),
                discount: funcs.weightedRandom(
                    [
                        { weight: 0.5, value: funcs.valuesFromArray({ values: discounts }) },
                        { weight: 0.5, value: funcs.default({ defaultValue: 0 }) }
                    ]
                )
            }
        }
    }));
}

main();

```
</Section>
<Section>
```ts
import type { AnyCockroachColumn } from "drizzle-orm/cockroach-core";
import { int4, numeric, cockroachTable, text, timestamp, varchar } from "drizzle-orm/cockroach-core";

export const customers = cockroachTable('customer', {
	id: varchar({ length: 256 }).primaryKey(),
	companyName: text().notNull(),
	contactName: text().notNull(),
	contactTitle: text().notNull(),
	address: text().notNull(),
	city: text().notNull(),
	postalCode: text(),
	region: text(),
	country: text().notNull(),
	phone: text().notNull(),
	fax: text(),
});

export const employees = cockroachTable(
	'employee',
	{
		id: int4().primaryKey(),
		lastName: text().notNull(),
		firstName: text(),
		title: text().notNull(),
		titleOfCourtesy: text().notNull(),
		birthDate: timestamp().notNull(),
		hireDate: timestamp().notNull(),
		address: text().notNull(),
		city: text().notNull(),
		postalCode: text().notNull(),
		country: text().notNull(),
		homePhone: text().notNull(),
		extension: int4().notNull(),
		notes: text().notNull(),
		reportsTo: int4().references((): AnyCockroachColumn => employees.id),
		photoPath: text(),
	},
);

export const orders = cockroachTable('order', {
	id: int4().primaryKey(),
	orderDate: timestamp().notNull(),
	requiredDate: timestamp().notNull(),
	shippedDate: timestamp(),
	shipVia: int4().notNull(),
	freight: numeric().notNull(),
	shipName: text().notNull(),
	shipCity: text().notNull(),
	shipRegion: text(),
	shipPostalCode: text(),
	shipCountry: text().notNull(),

	customerId: text().notNull().references(() => customers.id, { onDelete: 'cascade' }),

	employeeId: int4().notNull().references(() => employees.id, { onDelete: 'cascade' }),
});

export const suppliers = cockroachTable('supplier', {
	id: int4().primaryKey(),
	companyName: text().notNull(),
	contactName: text().notNull(),
	contactTitle: text().notNull(),
	address: text().notNull(),
	city: text().notNull(),
	region: text(),
	postalCode: text().notNull(),
	country: text().notNull(),
	phone: text().notNull(),
});

export const products = cockroachTable('product', {
	id: int4().primaryKey(),
	name: text().notNull(),
	quantityPerUnit: text().notNull(),
	unitPrice: numeric().notNull(),
	unitsInStock: int4().notNull(),
	unitsOnOrder: int4().notNull(),
	reorderLevel: int4().notNull(),
	discontinued: int4().notNull(),

	supplierId: int4().notNull().references(() => suppliers.id, { onDelete: 'cascade' }),
});

export const details = cockroachTable('order_detail', {
	unitPrice: numeric().notNull(),
	quantity: int4().notNull(),
	discount: numeric().notNull(),

	orderId: int4().notNull().references(() => orders.id, { onDelete: 'cascade' }),

	productId: int4().notNull().references(() => products.id, { onDelete: 'cascade' }),
});

```
</Section>
</CodeTabs>

## Limitations

#### Types limitations for `with`

Due to certain TypeScript limitations and the current API in Drizzle, it is not possible to properly infer references between tables, especially when circular dependencies between tables exist.

This means the `with` option will display all tables in the schema, and you will need to manually select the one that has a one-to-many relationship

<Callout title='warning'>
The `with` option works for one-to-many relationships. For example, if you have one `user` and many `posts`, you can use users `with` posts, but you cannot use posts `with` users
</Callout>

#### Type limitations for the third parameter in Drizzle tables:

Currently, we do not have type support for the third parameter in Drizzle tables. While it will work at runtime, it will not function correctly at the type level


Source: https://orm.drizzle.team/docs/cockroach/seed-versioning

import Callout from "@mdx/Callout.astro";
import TableWrapper from "@mdx/TableWrapper.astro";

# Versioning

`drizzle-seed` uses versioning to manage outputs for static and dynamic data. To ensure true 
determinism, ensure that values remain unchanged when using the same `seed` number. If changes are made to 
static data sources or dynamic data generation logic, the version will be updated, allowing
you to choose between sticking with the previous version or using the latest.

You can upgrade to the latest `drizzle-seed` version for new features, such as additional
generators, while maintaining deterministic outputs with a previous version if needed. This
is particularly useful when you need to rely on existing deterministic data while accessing new functionality.

```ts
await seed(db, schema, { version: '2' });
```

## History
<TableWrapper>
|          api version  |   npm version    |     Changed generators                    |
|  :--------------      | :--------------  | :-------------                            |
|       `v1`            | `0.1.1`          |                                           |
|       `v2`	          | `0.2.1`          |`string()`, `interval({ isUnique: true })` |
|       `v3`            | `0.4.0`          |`hash generating function`    			       |
|       `v4 (LTS) `     | `1.0.0-beta.8`   |`uuid` 								                     |
</TableWrapper>

<Callout collapsed="How it works under the hood?">
> This is not an actual API change; it is just an example of how we will proceed with `drizzle-seed` versioning.

For example, `lastName` generator was changed, and new version, `V2`, of this generator became available.

Later, `firstName` generator was changed, making `V3` version of this generator available.

|                  |       `V1`       |      `V2`       |   `V3(latest)`   |
| :--------------: | :--------------: | :-------------: | :--------------: |
| **LastNameGen**  | `LastNameGenV1`  | `LastNameGenV2` |                  |
| **FirstNameGen** | `FirstNameGenV1` |                 | `FirstNameGenV3` |

##### Use the `firstName` generator of version 3 and the `lastName` generator of version 2
```ts
await seed(db, schema);
```

If you are not ready to use latest generator version right away, you can specify max version to use

##### Use the `firstName` generator of version 1 and the `lastName` generator of version 2
```ts
await seed(db, schema, { version: '2' });
```

##### Use the `firstName` generator of version 1 and the `lastName` generator of version 1.
```ts
await seed(db, schema, { version: '1' });
```

</Callout>

## Version 2
#### Unique `interval` generator was changed

<Callout title='Reason for upgrade'>
An older version of the generator could produce intervals like `1 minute 60 seconds` and `2 minutes 0 seconds`, treating them as distinct intervals.
However, when the `1 minute 60 seconds` interval is inserted into a CockroachDB database, it is automatically converted to `2 minutes 0 seconds`. As a result, attempting to insert the `2 minutes 0 seconds` interval into a unique column afterwards will cause an error
</Callout>

You will be affected, if your table includes a unique column of type `interval`:

```ts
import { drizzle } from "drizzle-orm/cockroach";
import { cockroachTable, interval } from "drizzle-orm/cockroach-core";
import { seed } from "drizzle-seed";

const intervals = cockroachTable("intervals", {
    interval: interval().unique()
});

async function main() {
  const db = drizzle(process.env.DATABASE_URL!);

  await seed(db, { intervals });
}

main();
```

You will be affected, if you use the unique `interval` generator in your seeding script, as shown in the script below:

```ts
import { drizzle } from "drizzle-orm/cockroach";
import { cockroachTable, interval, char, varchar, text } from "drizzle-orm/cockroach-core";
import { seed } from "drizzle-seed";

const intervals = cockroachTable("intervals", {
    interval: interval().unique(),
    interval1: interval(),
    interval2: char({ length: 256 }).unique(),
    interval3: char({ length: 256 }),
    interval4: varchar().unique(),
    interval5: varchar(),
    interval6: text().unique(),
    interval7: text(),
});

async function main() {
  const db = drizzle(process.env.DATABASE_URL!);

  await seed(db, { intervals }).refine((f) => ({
    intervals: {
        columns: {
            interval: f.interval({ isUnique: true }),
            interval1: f.interval({ isUnique: true }),
            interval2: f.interval({ isUnique: true }),
            interval3: f.interval({ isUnique: true }),
            interval4: f.interval({ isUnique: true }),
            interval5: f.interval({ isUnique: true }),
            interval6: f.interval({ isUnique: true }),
            interval7: f.interval({ isUnique: true }),
        }
    }
  }));
}

main();
```

#### `string` generators were changed: both non-unique and unique

<Callout title='Reason to upgrade'>
Ability to generate a unique string based on the length of the text column (e.g., `varchar(20)`)
</Callout>

You will be affected, if your table includes a column of a text-like type with a maximum length parameter or a unique column of a text-like type:

```ts
import { drizzle } from "drizzle-orm/cockroach";
import { cockroachTable, char, varchar, text } from "drizzle-orm/cockroach-core";
import { seed } from "drizzle-seed";

const strings = cockroachTable("strings", {
    string2: char({ length: 256 }).unique(),
    string3: char({ length: 256 }),
    string4: varchar().unique(),
    string5: varchar({ length: 256 }).unique(),
    string6: varchar({ length: 256 }),
    string7: text().unique(),
});

async function main() {
  const db = drizzle(process.env.DATABASE_URL!);

  await seed(db, { strings });
}

main();
```

You will be affected, if you use the `string` generator in your seeding script, as shown in the script below:

```ts
import { drizzle } from "drizzle-orm/cockroach";
import { cockroachTable, char, varchar, text } from "drizzle-orm/cockroach-core";
import { seed } from "drizzle-seed";

const strings = cockroachTable("strings", {
    string1: char({ length: 256 }).unique(),
    string2: char({ length: 256 }),
    string3: char({ length: 256 }),
    string4: varchar(),
    string5: varchar().unique(),
    string6: varchar({ length: 256 }).unique(),
    string7: varchar({ length: 256 }),
    string8: varchar({ length: 256 }),
    string9: text().unique(),
    string10: text(),
});

async function main() {
  const db = drizzle(process.env.DATABASE_URL!);

  await seed(db, { strings }).refine((f) => ({
    strings: {
        columns: {
            string1: f.string({ isUnique: true }),
            string2: f.string(),
            string3: f.string({ isUnique: true }),
            string4: f.string({ isUnique: true }),
            string5: f.string({ isUnique: true }),
            string6: f.string({ isUnique: true }),
            string7: f.string(),
            string8: f.string({ isUnique: true }),
            string9: f.string({ isUnique: true }),
            string10: f.string({ isUnique: true }),
        }
    }
  }));
}

main();
```

## Version 3
#### `hash generating function was changed`

<Callout title='Reason to upgrade'>
The previous version of the hash generating function generated different hashes depending on whether Bun or Node.js was used, and hashes also varied across versions of Node.js.

The new hash generating function will generate the same hash regardless of the version of Node.js or Bun, resulting in deterministic data generation across all versions.
</Callout>

All generators will output different values compared to the previous version, even with the same seed number.

**Usage**
```ts
await seed(db, schema);
// or explicit
await seed(db, schema, { version: '3' });
```

**Switch to the old version**

The previous version of hash generating function is v1.
```ts
await seed(db, schema, { version: '1' });
```
To use the v2 generators while maintaining the v1 hash generating function:
```ts
await seed(db, schema, { version: '2' });
```

## Version 4
#### `uuid` generator was changed

<Callout title='Reason to upgrade'>
UUID values generated by the old version of the `uuid` generator fail Zod’s v4 UUID validation.

example
```ts
import { createSelectSchema } from 'drizzle-zod';
import { seed } from 'drizzle-seed';

await seed(db, { uuidTest: schema.uuidTest }, { count: 1 }).refine((funcs) => ({
		uuidTest: {
			columns: {
				col1: funcs.uuid()
			}
		}
	})
);

const uuidSelectSchema = createSelectSchema(schema.uuidTest);
const res = await db.select().from(schema.uuidTest);
// the line below will throw an error when using old version of uuid generator
uuidSelectSchema.parse(res[0]);
```
</Callout>

**Usage**
```ts
await seed(db, schema);
// or explicit
await seed(db, schema, { version: '4' });
```

**Switch to the old version**

The previous version of `uuid` generator is v1.
```ts
await seed(db, schema, { version: '1' });
```
To use the v2 generators while maintaining the v1 `uuid` generator:
```ts
await seed(db, schema, { version: '2' });
```
To use the v3 generators while maintaining the v1 `uuid` generator:
```ts
await seed(db, schema, { version: '3' });
```


Source: https://orm.drizzle.team/docs/cockroach/select

import CodeTabs from '@mdx/CodeTabs.astro';
import Callout from '@mdx/Callout.astro';
import Section from '@mdx/Section.astro';
import $count from '@mdx/$count-cockroach.mdx';

# SQL Select
Drizzle provides you the most SQL-like way to fetch data from your database, while remaining type-safe and composable.
It natively supports mostly every query feature and capability of every dialect,
and whatever it doesn't support yet, can be added by the user with the powerful [sql](/docs/cockroach/sql) operator.

For the following examples, let's assume you have a `users` table defined like this:

```typescript
import { cockroachTable, serial, string } from 'drizzle-orm/cockroach-core';

export const users = cockroachTable('users', {
  id: int4().primaryKey(),
  name: string().notNull(),
  age: int4(),
});
```

### Basic select
Select all rows from a table including all columns:

<Section>
```typescript
const result = await db.select().from(users);
/*
  {
    id: number;
    name: string;
    age: number | null;
  }[]
*/
```
```sql
select "id", "name", "age" from "users";
```
</Section>

Notice that the result type is inferred automatically based on the table definition, including columns nullability.

<Callout type="info">
Drizzle always explicitly lists columns in the `select` clause instead of using `select *`.<br />
This is required internally to guarantee the fields order in the query result, and is also generally considered a good practice.
</Callout>

### Partial select
In some cases, you might want to select only a subset of columns from a table.
You can do that by providing a selection object to the `.select()` method:
<Section>
```typescript copy
const result = await db.select({
  field1: users.id,
  field2: users.name,
}).from(users);

const { field1, field2 } = result[0];
```
```sql
select "id", "name" from "users";
```
</Section>

Like in SQL, you can use arbitrary expressions as selection fields, not just table columns:

<Section>
```typescript
const result = await db.select({
  id: users.id,
  lowerName: sql<string>`lower(${users.name})`,
}).from(users);
```
```sql
select "id", lower("name") from "users";
```
</Section>

<Callout type="warning">
By specifying `sql<string>`, you are telling Drizzle that the **expected** type of the field is `string`.<br />
If you specify it incorrectly (e.g. use `sql<number>` for a field that will be returned as a string), the runtime value won't match the expected type.
Drizzle cannot perform any type casts based on the provided type generic, because that information is not available at runtime.

If you need to apply runtime transformations to the returned value, you can use the [`.mapWith()`](/docs/cockroach/sql#sqlmapwith) method.
</Callout>

### Conditional select

You can have a dynamic selection object based on some condition:

```typescript
async function selectUsers(withName: boolean) {
  return db
    .select({
      id: users.id,
      ...(withName ? { name: users.name } : {}),
    })
    .from(users);
}

const result = await selectUsers(true);
```

### Distinct select

You can use `.selectDistinct()` instead of `.select()` to retrieve only unique rows from a dataset:
<Section>
```ts
await db.selectDistinct().from(users).orderBy(users.id, users.name);

await db.selectDistinct({ id: users.id }).from(users).orderBy(users.id);
```
```sql
select distinct "id", "name", "age" from "users" order by "users"."id", "users"."name";

select distinct "id" from "users" order by "users"."id";
```
</Section>

In CockroachDB, you can also use the `distinct on` clause to specify how the unique rows are determined:
<Section>
```ts
await db.selectDistinctOn([users.id]).from(users).orderBy(users.id);
await db.selectDistinctOn([users.name], { name: users.name }).from(users).orderBy(users.name);
```
```sql
select distinct on ("users"."id") "id", "name", "age" from "users" order by "users"."id";
select distinct on ("users"."name") "name" from "users" order by "users"."name";
```
</Section>

### Advanced select
Powered by TypeScript, Drizzle APIs let you build your select queries in a variety of flexible ways.

Sneak peek of advanced partial select, for more detailed advanced usage examples - see our [dedicated guide](/docs/cockroach/guides/include-or-exclude-columns).

<CodeTabs items={["example 1", "example 2", "example 3", "example 4"]}>
```ts
import { getColumns, sql } from 'drizzle-orm';

await db.select({
    ...getColumns(posts),
    titleLength: sql<number>`length(${posts.title})`,
  }).from(posts);
```
```ts
import { getColumns } from 'drizzle-orm';

const { content, ...rest } = getColumns(posts); // exclude "content" column
await db.select({ ...rest }).from(posts); // select all other columns
```
```ts
await db.query.posts.findMany({
  columns: {
    title: true,
  },
});
```
```ts
await db.query.posts.findMany({
  columns: {
    content: false,
  },
});
```
</CodeTabs>

## ---

### Filters

You can filter the query results using the [filter operators](/docs/cockroach/operators) in the `.where()` method:

<Section>
```typescript copy
import { eq, lt, gte, ne } from 'drizzle-orm';

await db.select().from(users).where(eq(users.id, 42));
await db.select().from(users).where(lt(users.id, 42));
await db.select().from(users).where(gte(users.id, 42));
await db.select().from(users).where(ne(users.id, 42));
...
```
```sql
select "id", "name", "age" from "users" where "users"."id" = 42;
select "id", "name", "age" from "users" where "users"."id" < 42;
select "id", "name", "age" from "users" where "users"."id" >= 42;
select "id", "name", "age" from "users" where "users"."id" <> 42;
```
</Section>

All filter operators are implemented using the [`sql`](/docs/cockroach/sql) function.
You can use it yourself to write arbitrary SQL filters, or build your own operators.
For inspiration, you can check how the operators provided by Drizzle are [implemented](https://github.com/drizzle-team/drizzle-orm/blob/main/drizzle-orm/src/sql/expressions/conditions.ts).
<Section>
```typescript copy
import { sql } from 'drizzle-orm';
import type { CockroachColumn } from "drizzle-orm/cockroach-core";

function equals42(col: CockroachColumn) {
  return sql`${col} = 42`;
}

await db.select().from(users).where(sql`${users.id} < 42`);
await db.select().from(users).where(sql`${users.id} = 42`);
await db.select().from(users).where(equals42(users.id));
await db.select().from(users).where(sql`${users.id} >= 42`);
await db.select().from(users).where(sql`${users.id} <> 42`);
await db.select().from(users).where(sql`lower(${users.name}) = 'aaron'`);
```
```sql
select "id", "name", "age" from "users" where "users"."id" < 42;
select "id", "name", "age" from "users" where "users"."id" = 42;
select "id", "name", "age" from "users" where "users"."id" = 42;
select "id", "name", "age" from "users" where "users"."id" >= 42;
select "id", "name", "age" from "users" where "users"."id" <> 42;
select "id", "name", "age" from "users" where lower("users"."name") = 'aaron';
```
</Section>

<Callout type='info'>
All the values provided to filter operators and to the `sql` function are parameterized automatically.
For example, this query:
```ts
await db.select().from(users).where(eq(users.id, 42));
```
will be translated to:
```sql
select "id", "name", "age" from "users" where "users"."id" = $1; -- params: [42]
```
</Callout>

Inverting condition with a `not` operator:
<Section>
```typescript copy
import { eq, not, sql } from 'drizzle-orm';

await db.select().from(users).where(not(eq(users.id, 42)));
await db.select().from(users).where(sql`not ${users.id} = 42`);
```
```sql
select "id", "name", "age" from "users" where not ("users"."id" = 42);
select "id", "name", "age" from "users" where not "users"."id" = 42;
```
</Section>

<Callout type="info">
You can safely alter schema, rename tables and columns
and it will be automatically reflected in your queries because of template interpolation,
as opposed to hardcoding column or table names when writing raw SQL.
</Callout>

### Combining filters
You can logically combine filter operators with `and()` and `or()` operators:
<Section>
```typescript copy
import { eq, and, sql } from 'drizzle-orm';

await db.select().from(users).where(
  and(
    eq(users.id, 42),
    eq(users.name, 'Dan')
  )
);
await db.select().from(users).where(sql`${users.id} = 42 and ${users.name} = 'Dan'`);
```
```sql
select "id", "name", "age" from "users" where (("users"."id" = 42) and ("users"."name" = 'Dan'));
select "id", "name", "age" from "users" where "users"."id" = 42 and "users"."name" = 'Dan';
```
</Section>

<Section>
```typescript copy
import { eq, or, sql } from 'drizzle-orm';

await db.select().from(users).where(
  or(
    eq(users.id, 42), 
    eq(users.name, 'Dan')
  )
);
await db.select().from(users).where(sql`${users.id} = 42 or ${users.name} = 'Dan'`);
```
```sql
select "id", "name", "age" from "users" where (("users"."id" = 42) or ("users"."name" = 'Dan'));
select "id", "name", "age" from "users" where "users"."id" = 42 or "users"."name" = 'Dan';
```
</Section>

### Advanced filters
In combination with TypeScript, Drizzle APIs provide you powerful and flexible ways to combine filters in queries.

Sneak peek of conditional filtering, for more detailed advanced usage examples - see our [dedicated guide](/docs/cockroach/guides/conditional-filters-in-query).
<CodeTabs items={["example 1", "example 2"]}>
```ts
const searchPosts = async (term?: string) => {
  await db
    .select()
    .from(posts)
    .where(term ? ilike(posts.title, term) : undefined);
};
await searchPosts();
await searchPosts('AI');
```
```ts
const searchPosts = async (filters: SQL[]) => {
  await db
    .select()
    .from(posts)
    .where(and(...filters));
};
const filters: SQL[] = [];
filters.push(ilike(posts.title, 'AI'));
filters.push(inArray(posts.category, ['Tech', 'Art', 'Science']));
filters.push(gt(posts.views, 200));
await searchPosts(filters);
```
</CodeTabs>

## ---

### Limit & offset
Use `.limit()` and `.offset()` to add limit and offset clauses to the query - for example, to implement pagination:

```ts
await db.select().from(users).limit(10);
await db.select().from(users).limit(10).offset(10);
```

```sql
select "id", "name", "age" from "users" limit 10;
select "id", "name", "age" from "users" limit 10 offset 10;
```

### Order By
Use `.orderBy()` to add `order by` clause to the query, sorting the results by the specified fields:
<Section>
```typescript
import { asc, desc } from 'drizzle-orm';

await db.select().from(users).orderBy(users.name);
await db.select().from(users).orderBy(desc(users.name));

// order by multiple fields
await db.select().from(users).orderBy(users.name, users.name2);
await db.select().from(users).orderBy(asc(users.name), desc(users.name2));
```
```sql
select "id", "name", "name2", "age" from "users" order by "users"."name";
select "id", "name", "name2", "age" from "users" order by "users"."name" desc;

select "id", "name", "name2", "age" from "users" order by "users"."name", "users"."name";
select "id", "name", "name2", "age" from "users" order by "users"."name" asc, "users"."name2" desc;
```
</Section>

### Advanced pagination
Powered by TypeScript, Drizzle APIs let you implement all possible SQL pagination and sorting approaches.

Sneak peek of advanced pagination, for more detailed advanced
usage examples - see our dedicated [limit offset pagination](/docs/cockroach/guides/limit-offset-pagination)
and [cursor pagination](/docs/cockroach/guides/cursor-based-pagination) guides.

<CodeTabs items={["example 1", "example 2", "example 3", "example 4"]}>
```ts
await db
  .select()
  .from(users)
  .orderBy(asc(users.id)) // order by is mandatory
  .limit(4) // the number of rows to return
  .offset(4); // the number of rows to skip
```
```ts
const getUsers = async (page = 1, pageSize = 3) => {
  return await db.query.users.findMany({
    orderBy: (users, { asc }) => asc(users.id),
    limit: pageSize,
    offset: (page - 1) * pageSize,
  });
};
await getUsers();
```
```ts
const getUsers = async (page = 1, pageSize = 10) => {
   const sq = db
    .select({ id: users.id })
    .from(users)
    .orderBy(users.id)
    .limit(pageSize)
    .offset((page - 1) * pageSize)
    .as('subquery');
   return await db.select().from(users).innerJoin(sq, eq(users.id, sq.id)).orderBy(users.id);
};
```
```ts
const nextUserPage = async (cursor?: number, pageSize = 3) => {
  return await db
    .select()
    .from(users)
    .where(cursor ? gt(users.id, cursor) : undefined) // if cursor is provided, get rows after it
    .limit(pageSize) // the number of rows to return
    .orderBy(asc(users.id)); // ordering
};
// pass the cursor of the last row of the previous page (id)
await nextUserPage(3);
```
</CodeTabs>

## ---

### WITH clause

<Callout>
  Check how to use WITH statement with [insert](/docs/cockroach/insert#with-insert-clause), [update](/docs/cockroach/update#with-update-clause), [delete](/docs/cockroach/delete#with-delete-clause)
</Callout>

Using the `with` clause can help you simplify complex queries by splitting them into smaller subqueries called common table expressions (CTEs):
<Section>
```typescript copy
const sq = db.$with('sq').as(db.select().from(users).where(eq(users.id, 42)));

const result = await db.with(sq).select().from(sq);
```
```sql
with "sq" as (select "id", "name", "age" from "users" where "users"."id" = 42)
select "id", "name", "age" from "sq";
```
</Section>

You can also provide `insert`, `update` and `delete` statements inside `with`

<Section>
```typescript copy
const sq = db.$with('sq').as(
    db.insert(users).values({ name: 'John' }).returning(),
);

const result = await db.with(sq).select().from(sq);
```
```sql
with "sq" as (insert into "users" ("id", "name", "age") values (default, 'John', default) returning "id", "name", "age")
select "id", "name", "age" from "sq";
```
</Section>

<Section>
```typescript copy
const sq = db.$with('sq').as(
    db.update(users).set({ age: 25 }).where(eq(users.name, 'John')).returning(),
);
const result = await db.with(sq).select().from(sq);
```
```sql
with "sq" as (update "users" set "age" = 25 where "users"."name" = 'John' returning "id", "name", "age") 
select "id", "name", "age" from "sq";
```
</Section>

<Section>
```typescript copy
const sq = db.$with('sq').as(
  db.delete(users).where(eq(users.name, 'John')).returning(),
);

const result = await db.with(sq).select().from(sq);
```
```sql
with "sq" as (delete from "users" where "users"."name" = $1 returning "id", "name", "age") 
select "id", "name", "age" from "sq";
```
</Section>

To select arbitrary SQL values as fields in a CTE and reference them in other CTEs or in the main query,
you need to add aliases to them:
```typescript copy

const sq = db.$with('sq').as(db.select({ 
  name: sql<string>`upper(${users.name})`.as('name'),
})
.from(users));

const result = await db.with(sq).select({ name: sq.name }).from(sq);
```
If you don't provide an alias, the field type will become `DrizzleTypeError` and you won't be able to reference it in other queries.
If you ignore the type error and still try to use the field,
you will get a runtime error, since there's no way to reference that field without an alias.

### Select from subquery
Just like in SQL, you can embed queries into other queries by using the subquery API:
<Section>
```typescript copy
const sq = db.select().from(users).where(eq(users.id, 42)).as('sq');
const result = await db.select().from(sq);
```
```sql
select "id", "name", "age" from (select "id", "name", "age" from "users" where "users"."id" = 42) "sq";
```
</Section>

Subqueries can be used in any place where a table can be used, for example in joins:
<Section>
```typescript copy
const sq = db.select().from(users).where(eq(users.id, 42)).as('sq');
const result = await db.select().from(users).leftJoin(sq, eq(users.id, sq.id));
```
```sql
select "users"."id", "users"."name", "users"."age", "sq"."id", "sq"."name", "sq"."age" from "users"
  left join (select "id", "name", "age" from "users" where "users"."id" = 42) "sq"
    on "users"."id" = "sq"."id";
```
</Section>

## ---

### Aggregations
With Drizzle, you can do aggregations using functions like `sum`, `count`, `avg`, etc. by
grouping and filtering with `.groupBy()` and `.having()` respectfully, same as you would do in raw SQL:

<Section>
```typescript
import { gt, sql } from "drizzle-orm";

await db.select({
  age: users.age,
  count: sql<number>`cast(count(${users.id}) as int)`,
})
  .from(users)
  .groupBy(users.age);

await db.select({
  age: users.age,
  count: sql<number>`cast(count(${users.id}) as int)`,
})
  .from(users)
  .groupBy(users.age)
  .having(({ count }) => gt(count, 1));
```
```sql
select "age", cast(count("id") as int)
  from "users"
  group by "users"."age";

select "age", cast(count("id") as int)
  from "users"
  group by "users"."age"
  having cast(count("users"."id") as int) > 1;
```
</Section>

<Callout type="info">
Alternatively, you can use [`.mapWith(Number)`](/docs/cockroach/sql#sqlmapwith) to cast the value to a number at runtime.

If you need count aggregation - we recommend using our [$count](/docs/cockroach/select#count) API
</Callout>

### Aggregations helpers

Drizzle has a set of wrapped `sql` functions, so you don't need to write
`sql` templates for common cases in your app

<Callout type="info">
 Remember, aggregation functions are often used with the GROUP BY clause of the SELECT statement. 
 So if you are selecting using aggregating functions and other columns in one query, 
 be sure to use the `.groupBy` clause
</Callout>

**count**

Returns the number of values in `expression`.
<Section>
```ts
import { count } from 'drizzle-orm'

await db.select({ value: count() }).from(users);
await db.select({ value: count(users.id) }).from(users);
```
```sql
select count(*) from "users";
select count("id") from "users";
```
```ts
// It's equivalent to writing
await db.select({ 
  value: sql`count(*)`.mapWith(Number) 
}).from(users);

await db.select({ 
  value: sql`count(${users.id})`.mapWith(Number) 
}).from(users);
```
</Section>

**countDistinct**

Returns the number of non-duplicate values in `expression`.
<Section>
```ts
import { countDistinct } from 'drizzle-orm'

await db.select({ value: countDistinct(users.id) }).from(users);
```
```sql
select count(distinct "id") from "users";
```
```ts
// It's equivalent to writing
await db.select({ 
  value: sql`count(distinct ${users.id})`.mapWith(Number) 
}).from(users);
```
</Section>

**avg**

Returns the average (arithmetic mean) of all non-null values in `expression`.
<Section>
```ts
import { avg } from 'drizzle-orm'

await db.select({ value: avg(users.id) }).from(users);
```
```sql
select avg("id") from "users";
```
```ts
// It's equivalent to writing
await db.select({ 
  value: sql`avg(${users.id})`.mapWith(String) 
}).from(users);
```
</Section>

**avgDistinct**

Returns the average (arithmetic mean) of all non-null values in `expression`.
<Section>
```ts
import { avgDistinct } from 'drizzle-orm'

await db.select({ value: avgDistinct(users.id) }).from(users);
```
```sql
select avg(distinct "id") from "users";
```
```ts
// It's equivalent to writing
await db.select({ 
  value: sql`avg(distinct ${users.id})`.mapWith(String) 
}).from(users);
```
</Section>

**sum**

Returns the sum of all non-null values in `expression`.
<Section>
```ts
import { sum } from 'drizzle-orm'

await db.select({ value: sum(users.id) }).from(users);
```
```sql
select sum("id") from "users";
```
```ts
// It's equivalent to writing
await db.select({ 
  value: sql`sum(${users.id})`.mapWith(String) 
}).from(users);
```
</Section>

**sumDistinct**

Returns the sum of all non-null and non-duplicate values in `expression`.
<Section>
```ts
import { sumDistinct } from 'drizzle-orm'

await db.select({ value: sumDistinct(users.id) }).from(users);
```
```sql
select sum(distinct "id") from "users";
```
```ts
// It's equivalent to writing
await db.select({ 
  value: sql`sum(distinct ${users.id})`.mapWith(String) 
}).from(users);
```
</Section>

**max**

Returns the maximum value in `expression`.
<Section>
```ts
import { max } from 'drizzle-orm'

await db.select({ value: max(users.id) }).from(users);
```
```sql
select max("id") from "users";
```
```ts
// It's equivalent to writing
await db.select({ 
  value: sql`max(${expression})`.mapWith(users.id) 
}).from(users);
```
</Section>

**min**

Returns the minimum value in `expression`.
<Section>
```ts
import { min } from 'drizzle-orm'

await db.select({ value: min(users.id) }).from(users);
```
```sql
select min("id") from "users";
```
```ts
// It's equivalent to writing
await db.select({ 
  value: sql`min(${users.id})`.mapWith(users.id) 
}).from(users);
```
</Section>

A more advanced example:

```typescript copy
const orders = cockroachTable("order", {
  id: int4().primaryKey(),
  orderDate: timestamp("order_date", { withTimezone: true }).notNull(),
  requiredDate: timestamp("required_date", { withTimezone: true }).notNull(),
  shippedDate: timestamp("shipped_date", { withTimezone: true }),
  shipVia: int4("ship_via").notNull(),
  freight: numeric("freight").notNull(),
  shipName: string("ship_name").notNull(),
  shipCity: string("ship_city").notNull(),
  shipRegion: string("ship_region"),
  shipPostalCode: string("ship_postal_code"),
  shipCountry: string("ship_country").notNull(),
  customerId: string("customer_id").notNull(),
  employeeId: int4("employee_id").notNull(),
});

const details = cockroachTable("order_detail", {
  unitPrice: numeric("unit_price").notNull(),
  quantity: int4("quantity").notNull(),
  discount: numeric("discount").notNull(),
  orderId: int4("order_id").notNull(),
  productId: int4("product_id").notNull(),
});


await db
  .select({
    id: orders.id,
    shippedDate: orders.shippedDate,
    shipName: orders.shipName,
    shipCity: orders.shipCity,
    shipCountry: orders.shipCountry,
    productsCount: sql<number>`cast(count(${details.productId}) as int)`,
    quantitySum: sql<number>`sum(${details.quantity})`,
    totalPrice: sql<number>`sum(${details.quantity} * ${details.unitPrice})`,
  })
  .from(orders)
  .leftJoin(details, eq(orders.id, details.orderId))
  .groupBy(orders.id)
  .orderBy(asc(orders.id))
```

### $count

<$count/>


Source: https://orm.drizzle.team/docs/cockroach/sequences

import Callout from '@mdx/Callout.astro';

# Sequences

Sequences in CockroachDB and CockroachDB are special single-row tables created to generate unique identifiers, often used for auto-incrementing primary key values. They provide a thread-safe way to generate unique sequential values across multiple sessions.

```ts
import { cockroachSchema, cockroachSequence } from 'drizzle-orm/cockroach-core';

// No params specified
export const customSequence = cockroachSequence('name');

// Sequence with params
export const customSequence = cockroachSequence('name', {
  startWith: 100,
  maxValue: 10000,
  minValue: 100,
  cache: 10,
  increment: 2,
});

// Sequence in custom schema
export const customSchema = cockroachSchema('custom_schema');
export const customSequence = customSchema.sequence('name');
```


Source: https://orm.drizzle.team/docs/cockroach/set-operations

import CodeTabs from '@mdx/CodeTabs.astro';
import CodeTab from '@mdx/CodeTab.astro';
import Callout from '@mdx/Callout.astro';
import Section from "@mdx/Section.astro";

# Set Operations

SQL set operations combine the results of multiple query blocks into a single result. 
The SQL standard defines the following three set operations: `UNION`, `INTERSECT`, `EXCEPT`, `UNION ALL`, `INTERSECT ALL`, `EXCEPT ALL`.

### Union
Combine all results from two query blocks into a single result, omitting any duplicates.

Get all names from customers and users tables without duplicates.

<CodeTabs items={["import-pattern", "builder-pattern", "schema.ts"]}>
	<CodeTab>
	```typescript copy
    import { union } from 'drizzle-orm/cockroach-core'
    import { users, customers } from './schema'

    const allNamesForUserQuery = db.select({ name: users.name }).from(users);

    const result = await union(
		allNamesForUserQuery,
		db.select({ name: customers.name }).from(customers)
	).limit(10);
    ```
    ```sql
    (select "name" from "sellers")
    union
    (select "name" from "customers")
    limit $1 -- params: [10]
    ```
    </CodeTab>
    <CodeTab>
    ```ts copy
    import { users, customers } from './schema'

    const result = await db
      .select({ name: users.name })
      .from(users)
      .union(db.select({ name: customers.name }).from(customers))
      .limit(10);
    ```
    ```sql
    (select "name" from "sellers")
    union
    (select "name" from "customers")
    limit $1 -- params: [10]
    ```
	</CodeTab>
    <CodeTab>
	```typescript copy
    import { int4, cockroachTable, string, varchar } from "drizzle-orm/cockroach-core";

    export const users = cockroachTable('sellers', {
        id: int4().primaryKey(),
        name: varchar({ length: 256 }).notNull(),
        address: string(),
    });
    
    export const customers = cockroachTable('customers', {
        id: int4().primaryKey(),
        name: varchar({ length: 256 }).notNull(),
        city: string(),
        email: varchar({ length: 256 }).notNull()
    });
    ```
    </CodeTab>
  </CodeTabs>

### Union All
Combine all results from two query blocks into a single result, with duplicates.

Let's consider a scenario where you have two tables, one representing online sales and the other 
representing in-store sales. In this case, you want to combine the data from both tables into a
single result set. Since there might be duplicate transactions, 
you want to keep all the records and not eliminate duplicates.

<CodeTabs items={["import-pattern", "builder-pattern", "schema.ts"]}>
	<CodeTab>
	```typescript copy
    import { unionAll } from 'drizzle-orm/cockroach-core'
    import { onlineSales, inStoreSales } from './schema'

    const onlineTransactions = db.select({ transaction: onlineSales.transactionId }).from(onlineSales);
    const inStoreTransactions = db.select({ transaction: inStoreSales.transactionId }).from(inStoreSales);

    const result = await unionAll(onlineTransactions, inStoreTransactions);
    ```
    ```sql
    (select "transaction_id" from "online_sales")
    union all
    (select "transaction_id" from "in_store_sales")
    ```
    </CodeTab>
    <CodeTab>
    ```ts copy
    import { onlineSales, inStoreSales } from './schema'

    const result = await db
      .select({ transaction: onlineSales.transactionId })
      .from(onlineSales)
      .unionAll(
        db.select({ transaction: inStoreSales.transactionId }).from(inStoreSales)
      );
    ```
    ```sql
    (select "transaction_id" from "online_sales")
    union all
    (select "transaction_id" from "in_store_sales")
    ```
	</CodeTab>
    <CodeTab>
	```typescript copy
    import { int4, cockroachTable, timestamp } from "drizzle-orm/cockroach-core";

    export const onlineSales = cockroachTable('online_sales', {
        transactionId: int4('transaction_id').primaryKey(),
        productId: int4('product_id').unique(),
        quantitySold: int4('quantity_sold'),
        saleDate: timestamp('sale_date', { mode: 'date' }),
    });
    
    export const inStoreSales = cockroachTable('in_store_sales', {
        transactionId: int4('transaction_id').primaryKey(),
        productId: int4('product_id').unique(),
        quantitySold: int4('quantity_sold'),
        saleDate: timestamp('sale_date', { mode: 'date' }),
    });
    ```
    </CodeTab>
  </CodeTabs>

### Intersect
Combine only those rows which the results of two query blocks have in common, omitting any duplicates.

Suppose you have two tables that store information about students' course enrollments. 
You want to find the courses that are common between two different departments,
but you want distinct course names, and you're not interested in counting multiple 
enrollments of the same course by the same student.

In this scenario, you want to find courses that are common between the two departments but don't want 
to count the same course multiple times even if multiple students from the same department are enrolled in it.

<CodeTabs items={["import-pattern", "builder-pattern", "schema.ts"]}>
	<CodeTab>
	```typescript copy
    import { intersect } from 'drizzle-orm/cockroach-core'
    import { depA, depB } from './schema'

    const departmentACourses = db.select({ courseName: depA.courseName }).from(depA);
    const departmentBCourses = db.select({ courseName: depB.courseName }).from(depB);

    const result = await intersect(departmentACourses, departmentBCourses);
    ```
    ```sql
    (select "course_name" from "department_a_courses")
    intersect
    (select "course_name" from "department_b_courses")
    ```
	</CodeTab>
    <CodeTab>
    ```typescript copy
    import { depA, depB } from './schema'

    const result = await db
      .select({ courseName: depA.courseName })
      .from(depA)
      .intersect(db.select({ courseName: depB.courseName }).from(depB));
    ```
    ```sql
    (select "course_name" from "department_a_courses")
    intersect
    (select "course_name" from "department_b_courses")
    ```
    </CodeTab>
    <CodeTab>
	```typescript copy
    import { int4, cockroachTable, varchar } from "drizzle-orm/cockroach-core";

    export const depA = cockroachTable('department_a_courses', {
        studentId: int4('student_id'),
        courseName: varchar('course_name').notNull(),
    });
    
    export const depB = cockroachTable('department_b_courses', {
        studentId: int4('student_id'),
        courseName: varchar('course_name').notNull(),
    });
    ```
    </CodeTab>
  </CodeTabs>

### Intersect All
Combine only those rows which the results of two query blocks have in common, with duplicates.

Let's consider a scenario where you have two tables containing data about customer orders, and you want 
to identify products that are ordered by both regular customers and VIP customers. In this case, 
you want to keep track of the quantity of each product, even if it's ordered multiple times by 
different customers.

In this scenario, you want to find products that are ordered by both regular customers and VIP customers, 
but you want to retain the quantity information, even if the same product is ordered multiple 
times by different customers.

<CodeTabs items={["import-pattern", "builder-pattern", "schema.ts"]}>
	<Section>
	```typescript copy
    import { intersectAll } from 'drizzle-orm/cockroach-core'
    import { regularCustomerOrders, vipCustomerOrders } from './schema'

    const regularOrders = db.select({ 
        productId: regularCustomerOrders.productId,
        quantityOrdered: regularCustomerOrders.quantityOrdered }
    ).from(regularCustomerOrders);

    const vipOrders = db.select({ 
        productId: vipCustomerOrders.productId,
        quantityOrdered: vipCustomerOrders.quantityOrdered }
    ).from(vipCustomerOrders);

    const result = await intersectAll(regularOrders, vipOrders);
    ```
    ```sql
    (select "product_id", "quantity_ordered" from "regular_customer_orders")
    intersect all
    (select "product_id", "quantity_ordered" from "vip_customer_orders")
    ```
	</Section>
	<Section>
    ```ts copy
    import { regularCustomerOrders, vipCustomerOrders } from './schema'

    const result = await db
        .select({
          productId: regularCustomerOrders.productId,
          quantityOrdered: regularCustomerOrders.quantityOrdered,
        })
        .from(regularCustomerOrders)
        .intersectAll(
          db
            .select({
              productId: vipCustomerOrders.productId,
              quantityOrdered: vipCustomerOrders.quantityOrdered,
            })
            .from(vipCustomerOrders)
        );
    ```
    ```sql
    (select "product_id", "quantity_ordered" from "regular_customer_orders")
    intersect all
    (select "product_id", "quantity_ordered" from "vip_customer_orders")
    ```
	</Section>
    <Section>
	```typescript copy
    import { int4, cockroachTable } from "drizzle-orm/cockroach-core";

    export const regularCustomerOrders = cockroachTable('regular_customer_orders', {
        customerId: int4('customer_id').primaryKey(),
        productId: int4('product_id').notNull(),
        quantityOrdered: int4('quantity_ordered').notNull(),
    });
    
    export const vipCustomerOrders = cockroachTable('vip_customer_orders', {
        customerId: int4('customer_id').primaryKey(),
        productId: int4('product_id').notNull(),
        quantityOrdered: int4('quantity_ordered').notNull(),
    });
    ```
    </Section>
  </CodeTabs>

### Except
For two query blocks A and B, return all results from A which are not also present in B, omitting any duplicates.

Suppose you have two tables that store information about employees' project assignments. 
You want to find the projects that are unique to one department 
and not shared with another department, excluding duplicates.

In this scenario, you want to identify the projects that are exclusive to one department and
not shared with the other department. You don't want to count the same project 
multiple times, even if multiple employees from the same department are assigned to it.

<CodeTabs items={["import-pattern", "builder-pattern", "schema.ts"]}>
	<CodeTab>
	```typescript copy
    import { except } from 'drizzle-orm/cockroach-core'
    import { depA, depB } from './schema'

    const departmentACourses = db.select({ courseName: depA.projectsName }).from(depA);
    const departmentBCourses = db.select({ courseName: depB.projectsName }).from(depB);

    const result = await except(departmentACourses, departmentBCourses);
    ```
    ```sql
    (select "projects_name" from "department_a_projects")
    except
    (select "projects_name" from "department_b_projects")
    ```
	</CodeTab>
    <CodeTab>
    ```ts copy
    import { depA, depB } from './schema'

    const result = await db
        .select({ courseName: depA.projectsName })
        .from(depA)
        .except(db.select({ courseName: depB.projectsName }).from(depB));
    ```
    ```sql
    (select "projects_name" from "department_a_projects")
    except
    (select "projects_name" from "department_b_projects")
    ```
    </CodeTab>
    <CodeTab>
	```typescript copy
    import { int4, cockroachTable, varchar } from "drizzle-orm/cockroach-core";

    export const depA = cockroachTable('department_a_projects', {
        employeeId: int4('employee_id'),
        projectsName: varchar('projects_name').notNull(),
    });
    
    export const depB = cockroachTable('department_b_projects', {
        employeeId: int4('employee_id'),
        projectsName: varchar('projects_name').notNull(),
    });
    ```
    </CodeTab>
  </CodeTabs>

### Except All
For two query blocks A and B, return all results from A which are not also present in B, with duplicates.

Let's consider a scenario where you have two tables containing data about customer orders, and you want to 
identify products that are exclusively ordered by regular customers (without VIP customers). 
In this case, you want to keep track of the quantity of each product, even if it's ordered multiple times by different regular customers.

In this scenario, you want to find products that are exclusively ordered by regular customers and not 
ordered by VIP customers. You want to retain the quantity information, even if the same product is ordered multiple times by different regular customers.

<CodeTabs items={["import-pattern", "builder-pattern", "schema.ts"]}>
	<CodeTab>
	```typescript copy
    import { exceptAll } from 'drizzle-orm/cockroach-core'
    import { regularCustomerOrders, vipCustomerOrders } from './schema'

    const regularOrders = db.select({ 
        productId: regularCustomerOrders.productId,
        quantityOrdered: regularCustomerOrders.quantityOrdered }
    ).from(regularCustomerOrders);

    const vipOrders = db.select({ 
        productId: vipCustomerOrders.productId,
        quantityOrdered: vipCustomerOrders.quantityOrdered }
    ).from(vipCustomerOrders);

    const result = await exceptAll(regularOrders, vipOrders);
    ```
    ```sql
    (select "product_id", "quantity_ordered" from "regular_customer_orders")
    except all
    (select "product_id", "quantity_ordered" from "vip_customer_orders")
    ```
	</CodeTab>
    <CodeTab>
    ```ts copy
    import { regularCustomerOrders, vipCustomerOrders } from './schema'
 
    const result = await db
        .select({
          productId: regularCustomerOrders.productId,
          quantityOrdered: regularCustomerOrders.quantityOrdered,
        })
        .from(regularCustomerOrders)
        .exceptAll(
          db
            .select({
              productId: vipCustomerOrders.productId,
              quantityOrdered: vipCustomerOrders.quantityOrdered,
            })
            .from(vipCustomerOrders)
        );
    ```
    ```sql
    (select "product_id", "quantity_ordered" from "regular_customer_orders")
    except all
    (select "product_id", "quantity_ordered" from "vip_customer_orders")
    ```
    </CodeTab>
	<CodeTab>
	```typescript copy
    import { int4, cockroachTable } from "drizzle-orm/cockroach-core";

    export const regularCustomerOrders = cockroachTable('regular_customer_orders', {
        customerId: int4('customer_id').primaryKey(),
        productId: int4('product_id').notNull(),
        quantityOrdered: int4('quantity_ordered').notNull(),
    });
    
    export const vipCustomerOrders = cockroachTable('vip_customer_orders', {
        customerId: int4('customer_id').primaryKey(),
        productId: int4('product_id').notNull(),
        quantityOrdered: int4('quantity_ordered').notNull(),
    });
    ```
    </CodeTab>
  </CodeTabs>


Source: https://orm.drizzle.team/docs/cockroach/sql-schema-declaration

import Callout from '@mdx/Callout.astro';
import SimpleLinkCards from '@mdx/SimpleLinkCards.astro';
import CodeTabs from "@mdx/CodeTabs.astro";
import Section from '@mdx/Section.astro';
import Flex from "@mdx/Flex.astro"
import LinksList from "@mdx/LinksList.astro"

# Drizzle schema

Drizzle lets you define a schema in TypeScript with various models and properties supported by the underlying database. 
When you define your schema, it serves as the source of truth for future modifications in queries (using Drizzle-ORM)
and migrations (using Drizzle-Kit).

<Callout> 
If you are using Drizzle-Kit for the migration process, make sure to export all the models defined in your schema files so that Drizzle-Kit can import them and use them in the migration diff process. 
</Callout>

<CodeTabs items={["Using imports", "Using callback", "Using import *"]}>
```ts
import { int4, cockroachTable, varchar } from "drizzle-orm/cockroach-core";

export const usersTable = cockroachTable("users", {
  id: int4().primaryKey().generatedAlwaysAsIdentity(),
  name: varchar().notNull(),
  age: int4().notNull(),
  email: varchar().notNull().unique(),
});
```
```ts
import { cockroachTable } from "drizzle-orm/cockroach-core";

export const usersTable = cockroachTable("users", (t) => ({
  id: t.int4().primaryKey().generatedAlwaysAsIdentity(),
  name: t.varchar().notNull(),
  age: t.int4().notNull(),
  email: t.varchar().notNull().unique(),
}));
```
```ts
import * as p from "drizzle-orm/cockroach-core";

export const usersTable = p.cockroachTable("users", {
  id: p.int4().primaryKey().generatedAlwaysAsIdentity(),
  name: p.varchar().notNull(),
  age: p.int4().notNull(),
  email: p.varchar().notNull().unique(),
});
```
</CodeTabs>

## Organize your schema files 
You can declare your SQL schema directly in TypeScript either in a single `schema.ts` file,
or you can spread them around — whichever you prefer, all the freedom!

#### Schema in 1 file
The most common way to declare your schema with Drizzle is to put all your tables into one `schema.ts` file.

> Note: You can name your schema file whatever you like. For example, it could be `models.ts`, or something else.

This approach works well if you don't have too many table models defined, or if you're okay with keeping them all in one file

Example:
```plaintext
📦 <project root>
 └ 📂 src
    └ 📂 db
       └ 📜 schema.ts
```

In the `drizzle.config.ts` file, you need to specify the path to your schema file. With this configuration, Drizzle will 
read from the `schema.ts` file and use this information during the migration generation process. For more information 
about the `drizzle.config.ts` file and migrations with Drizzle, please check: [link](/docs/cockroach/drizzle-config-file)
```ts
import { defineConfig } from "drizzle-kit";

export default defineConfig({
  dialect: 'cockroach',
  schema: './src/db/schema.ts'
})
```

#### Schema in multiple files

You can place your Drizzle models — such as tables, enums, sequences, etc. — not only in one file but in any file you prefer. 
The only thing you must ensure is that you export all the models from those files so that the Drizzle kit can import 
them and use them in migrations.

One use case would be to separate each table into its own file.
```plaintext
📦 <project root>
 └ 📂 src
    └ 📂 db
       └ 📂 schema
          ├ 📜 users.ts
          ├ 📜 countries.ts
          ├ 📜 cities.ts
          ├ 📜 products.ts
          ├ 📜 clients.ts
          └ 📜 etc.ts
```

In the `drizzle.config.ts` file, you need to specify the path to your schema folder. With this configuration, Drizzle will 
read from the `schema` folder and find all the files recursively and get all the drizzle tables from there. For more information 
about the `drizzle.config.ts` file and migrations with Drizzle, please check: [link](/docs/cockroach/drizzle-config-file)

```ts
import { defineConfig } from "drizzle-kit";

export default defineConfig({
  dialect: 'cockroach',
  schema: './src/db/schema'
})
```

You can also group them in any way you like, such as creating groups for user-related tables, messaging-related tables, product-related tables, etc. 
```plaintext
📦 <project root>
 └ 📂 src
    └ 📂 db
       └ 📂 schema
          ├ 📜 users.ts
          ├ 📜 messaging.ts
          └ 📜 products.ts
```

## Shape your data schema

Drizzle schema consists of several model types from database you are using. With drizzle you can specify:
- Tables with columns, constraints, etc.
- Schemas
- Enums
- Sequences
- Views
- Materialized Views
- etc.

Let's go one by one and check how the schema should be defined with drizzle

#### **Tables and columns declaration** 

A table in Drizzle should be defined with at least 1 column, the same as it should be done in database. There is one important thing to know,
there is no such thing as a common table object in drizzle. You need to choose a dialect you are using, Cockroach, MySQL, SQLite, etc.

![](@/assets/images/table-structure.svg)

```ts copy
import { cockroachTable, int4 } from "drizzle-orm/cockroach-core"

export const users = cockroachTable('users', {
  id: int4()
});
```

By default, Drizzle will use the TypeScript key names for columns in database queries. 
Therefore, the schema and query from the example will generate the SQL query shown below

<Callout>
This example uses a db object, whose initialization is not covered in this part of the documentation. To learn how to connect to the database, please refer to the [Connections Docs](/docs/cockroach/get-started-cockroach)
</Callout>

\
**TypeScript key = database key**
<Section>
```ts
// schema.ts
import { int4, cockroachTable, varchar } from "drizzle-orm/cockroach-core";

export const users = cockroachTable('users', {
  id: int4(),
  first_name: varchar()
})
```
```ts
// query.ts
await db.select().from(users);
```
```sql
SELECT "id", "first_name" from users;
```
</Section>

If you want to use different names in your TypeScript code and in the database, you can use column aliases

<Section>
```ts
// schema.ts
import { int4, cockroachTable, varchar } from "drizzle-orm/cockroach-core";

export const users = cockroachTable('users', {
  id: int4(),
  firstName: varchar('first_name')
})
```
```ts
// query.ts
await db.select().from(users);
```
```sql
SELECT "id", "first_name" from users;
```
</Section>

### Camel and Snake casing

Database model names often use `snake_case` conventions, while in TypeScript, it is common to use `camelCase` for naming models.
This can lead to a lot of alias definitions in the schema. To address this, Drizzle provides a way to automatically
map `camelCase` from TypeScript to `snake_case` in the database via a dedicated builder.

Use the `snakeCase` or `camelCase` builder from `drizzle-orm/cockroach-core` to declare a table whose column keys are
automatically mapped to the chosen database naming convention

<Section>
```ts {2,4,11,12}
// schema.ts
import { snakeCase, camelCase } from 'drizzle-orm/cockroach-core';

export const users = snakeCase.table('users', {
  id: int4().primaryKey(),
  fullName: text(),        // → full_name in DB
  createdAt: timestamp(),  // → created_at in DB
});

// Available on all entity types:
snakeCase.table / snakeCase.view / snakeCase.materializedView / snakeCase.schema
camelCase.table / camelCase.view / camelCase.materializedView / camelCase.schema
```
```ts
// db.ts
import { drizzle } from "drizzle-orm/cockroach";

const db = drizzle({ connection: process.env.DATABASE_URL })
```
```ts
// query.ts
await db.select().from(users);
```
```sql
select "id", "full_name", "created_at" from "users"
```
</Section>

### Advanced

There are a few tricks you can use with Drizzle ORM. As long as Drizzle is entirely in TypeScript files, 
you can essentially do anything you would in a simple TypeScript project with your code.

One common feature is to separate columns into different places and then reuse them. 
For example, consider the `updated_at`, `created_at`, and `deleted_at` columns. Many tables/models may need these 
three fields to track and analyze the creation, deletion, and updates of entities in a system

We can define those columns in a separate file and then import and spread them across all the table objects you have

<Section>
```ts
// columns.helpers.ts
export const timestamps = {
  updated_at: timestamp(),
  created_at: timestamp().defaultNow().notNull(),
  deleted_at: timestamp(),
}
```
```ts
// users.sql.ts
export const users = cockroachTable('users', {
  id: int4(),
  ...timestamps
})
```
```ts
// posts.sql.ts
export const posts = cockroachTable('posts', {
  id: int4(),
  ...timestamps
})
```
</Section>

#### **Schemas**

\
In cockroach, there is an entity called a `schema` (which we believe should be called `folders`). This creates a structure in cockroach:

![](@/assets/images/postgresql-db-structure.png)

You can manage your cockroach schemas with `cockroachSchema` and place any other models inside it.

Define the schema you want to manage using Drizzle
```ts
import { cockroachSchema } from "drizzle-orm/cockroach-core"

export const customSchema = cockroachSchema('custom');
```

Then place the table inside the schema object
```ts {5-7}
import { int4, cockroachSchema } from "drizzle-orm/cockroach-core";

export const customSchema = cockroachSchema('custom');

export const users = customSchema.table('users', {
  id: int4()
})
```

### Example

Once you know the basics, let's define a schema example for a real project to get a better view and understanding

> All examples will use `generateUniqueString`. The implementation for it will be provided after all the schema examples

```ts copy
import type { AnyCockroachColumn } from "drizzle-orm/cockroach-core";
import { cockroachEnum, cockroachTable as table } from "drizzle-orm/cockroach-core";
import * as t from "drizzle-orm/cockroach-core";

export const rolesEnum = cockroachEnum("roles", ["guest", "user", "admin"]);

export const users = table(
  "users",
  {
    id: t.int4().primaryKey().generatedAlwaysAsIdentity(),
    firstName: t.varchar("first_name", { length: 256 }),
    lastName: t.varchar("last_name", { length: 256 }),
    email: t.varchar().notNull(),
    invitee: t.int4().references((): AnyCockroachColumn => users.id),
    role: rolesEnum().default("guest"),
  },
  (table) => [
    t.uniqueIndex("email_idx").on(table.email)
  ]
);

export const posts = table(
  "posts",
  {
    id: t.int4().primaryKey().generatedAlwaysAsIdentity(),
    slug: t.varchar().$default(() => generateUniqueString(16)),
    title: t.varchar({ length: 256 }),
    ownerId: t.int4("owner_id").references(() => users.id),
  },
  (table) => [
    t.uniqueIndex("slug_idx").on(table.slug),
    t.index("title_idx").on(table.title),
  ]
);

export const comments = table("comments", {
  id: t.int4().primaryKey().generatedAlwaysAsIdentity(),
  text: t.varchar({ length: 256 }),
  postId: t.int4("post_id").references(() => posts.id),
  ownerId: t.int4("owner_id").references(() => users.id),
});
```

**`generateUniqueString` implementation:**
```ts
function generateUniqueString(length: number = 12): string {
  const characters =
    "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
  let uniqueString = "";

  for (let i = 0; i < length; i++) {
    const randomIndex = Math.floor(Math.random() * characters.length);
    uniqueString += characters[randomIndex];
  }

  return uniqueString;
}
```

#### What's next?
<br/>
<Flex>
  <LinksList 
    title='Manage schema'
    links={[
        ["Column types", "/docs/cockroach/column-types"], 
        ["Indexes and Constraints", "/docs/cockroach/indexes-constraints"],
        ["Database Views", "/docs/cockroach/views"],
        ["Database Schemas", "/docs/cockroach/schemas"],
        ["Sequences", "/docs/cockroach/sequences"],
      ]}
  />
  <LinksList 
    title='Zero to Hero'
    links={[
        ["Database connection", "/docs/cockroach/connect-overview"], 
        ["Data querying", "/docs/cockroach/data-querying"], 
        ["Migrations", "/docs/cockroach/migrations"], 
      ]}
  />
</Flex>


Source: https://orm.drizzle.team/docs/cockroach/sql

import Callout from '@mdx/Callout.astro';
import Section from '@mdx/Section.astro';

# Magical `sql` operator 🪄

When working with an ORM library, there may be cases where you find it challenging to write a
specific query using the provided ORM syntax. In such situations, you can resort to using
raw queries, which involve constructing a query as a raw string. However, raw queries often
lack the benefits of type safety and query parameterization.

To address this, many libraries have introduced the concept of an `sql` template. This template 
allows you to write more type-safe and parameterized queries, enhancing the overall safety and 
flexibility of your code. Drizzle, being a powerful ORM library, also supports the sql template.

With Drizzle's `sql` template, you can go even further in crafting queries. If you encounter 
difficulties in writing an entire query using the library's query builder, you can selectively
use the `sql` template within specific sections of the Drizzle query. This flexibility enables you 
to employ the sql template in partial SELECT statements, WHERE clauses, ORDER BY clauses, HAVING
clauses, GROUP BY clauses, and even in relational query builders.

By leveraging the capabilities of the sql template in Drizzle, you can maintain the advantages 
of type safety and query parameterization while achieving the desired query structure and complexity.
This empowers you to create more robust and maintainable code within your application.

## sql`` template

One of the most common usages you may encounter in other ORMs as well 
is the ability to use `sql` queries as-is for raw queries.

```typescript copy
import { sql } from 'drizzle-orm' 

const id = 69;
await db.execute(sql`select * from ${usersTable} where ${usersTable.id} = ${id}`)
```

It will generate the current query

```sql
select * from "users" where "users"."id" = $1; --> [69]
```

Any tables and columns provided to the sql parameter are automatically mapped to their corresponding SQL 
syntax with escaped names for tables, and the escaped table names are appended to column names. 

Additionally, any dynamic parameters such as `${id}` will be mapped to the $1 placeholder, 
and the corresponding values will be moved to an array of values that are passed separately to the database. 

This approach effectively prevents any potential SQL Injection vulnerabilities.

## `sql<T>`

<Callout type="info" emoji="ℹ️">
    Please note that `sql<T>` does not perform any runtime mapping. The type you define using `sql<T>` is
    purely a helper for Drizzle. It is important to understand that there is no feasible way to 
    determine the exact type dynamically, as SQL queries can be highly versatile and customizable. 
</Callout>

You can define a custom type in Drizzle to be used in places where fields require a specific type other than `unknown`.

This feature is particularly useful in partial select queries, ensuring consistent typing for selected fields:

```typescript
// without sql<T> type defined
const response: { lowerName: unknown }[] = await db.select({
    lowerName: sql`lower(${usersTable.id})`
}).from(usersTable);

// with sql<T> type defined
const response: { lowerName: string }[] = await db.select({
    lowerName: sql<string>`lower(${usersTable.id})`
}).from(usersTable);
```

## `sql``.mapWith()`

For the cases you need to make a runtime mapping for values passed from database driver to drizzle you can use `.mapWith()`

This function accepts different values, that will map response in runtime.

You can replicate a specific column mapping strategy as long as
the interface inside mapWith is the same interface that is implemented by Column.

```typescript
const usersTable = cockroachTable('users', {
    id: int4('id').primaryKey(),
    name: string('name').notNull(),
});

//  at runtime this values will be mapped same as `text` column is mapped in drizzle
sql`...`.mapWith(usersTable.name);
```

You can also pass your own implementation for the `DriverValueDecoder` interface:

```ts 
sql``.mapWith({
	mapFromDriverValue: (value: any) => {
		const mappedValue = value;
		// mapping you want to apply
		return mappedValue;
	},
});
    
// or
sql``.mapWith(Number);
```

## `sql``.as<T>()`

In different cases, it can sometimes be challenging to determine how to name a custom field that you want to use.
You may encounter situations where you need to explicitly specify an alias for a 
field that will be selected. This can be particularly useful when dealing with complex queries. 

To address these scenarios, we have introduced a helpful `.as('alias_name')` helper, which allows 
you to define an alias explicitly. By utilizing this feature, you can provide a clear and meaningful 
name for the field, making your queries more intuitive and readable.

<Section>
```typescript
sql`lower(${usersTable.name})`.as('lower_name')
```
```sql
... "users"."name" as lower_name ...
```
</Section>

## `sql.raw()`

There are cases where you may not need to create parameterized values from input or map tables/columns to escaped ones. 
Instead, you might simply want to generate queries as they are. For such situations, we provide the `sql.raw()` function.

The `sql.raw()` function allows you to include raw SQL statements within your queries without any additional processing or escaping.
This can be useful when you have pre-constructed SQL statements or when you need to incorporate complex or dynamic 
SQL code directly into your queries.

<Section>
```typescript
sql.raw(`select * from users where id = ${12}`);
// vs
sql`select * from users where id = ${12}`;
```
```sql
select * from users where id = 12;
--> vs
select * from users where id = $1; --> [12]
```
</Section>

You can also utilize `sql.raw()` within the sql function, enabling you to include any raw string
without escaping it through the main `sql` template function.

By using `sql.raw()` inside the `sql` function, you can incorporate unescaped raw strings 
directly into your queries. This can be particularly useful when you have specific
SQL code or expressions that should remain untouched by the template function's automatic escaping or modification.

<Section>
```typescript
sql`select * from ${usersTable} where id = ${12}`;
// vs
sql`select * from ${usersTable} where id = ${sql.raw(12)}`;
```
```sql
select * from "users" where id = $1; --> [12]
--> vs
select * from "users" where id = 12;
```
</Section>

## sql.fromList()

The `sql` template generates sql chunks, which are arrays of SQL parts that will be concatenated 
into the query and params after applying the SQL to the database or query in Drizzle.

In certain scenarios, you may need to aggregate these chunks into an array using custom business 
logic and then concatenate them into a single SQL statement that can be passed to the database or query.
For such cases, the fromList function can be quite useful.

The fromList function allows you to combine multiple SQL chunks into a single SQL statement. 
You can use it to aggregate and concatenate the individual SQL parts according to your specific 
requirements and then obtain a unified SQL query that can be executed.

<Section>
```typescript
const sqlChunks: SQL[] = [];

sqlChunks.push(sql`select * from users`);

// some logic

sqlChunks.push(sql` where `);

// some logic

for (let i = 0; i < 5; i++) {
	sqlChunks.push(sql`id = ${i}`);

	if (i === 4) continue;
	sqlChunks.push(sql` or `);
}

const finalSql: SQL = sql.fromList(sqlChunks)
```
```sql
select * from users where id = $1 or id = $2 or id = $3 or id = $4 or id = $5; --> [0, 1, 2, 3, 4]
```
</Section>

## sql.join()

Indeed, the `sql.join` function serves a similar purpose to the fromList helper. 
However, it provides additional flexibility when it comes to handling spaces between
SQL chunks or specifying custom separators for concatenating the SQL chunks.

With `sql.join`, you can concatenate SQL chunks together using a specified separator. 
This separator can be any string or character that you want to insert between the chunks. 

This is particularly useful when you have specific requirements for formatting or delimiting 
the SQL chunks. By specifying a custom separator, you can achieve the desired structure and formatting 
in the final SQL query.

<Section>
```typescript
const sqlChunks: SQL[] = [];

sqlChunks.push(sql`select * from users`);

// some logic

sqlChunks.push(sql`where`);

// some logic

for (let i = 0; i < 5; i++) {
	sqlChunks.push(sql`id = ${i}`);

if (i === 4) continue;
    sqlChunks.push(sql`or`);
}

const finalSql: SQL = sql.join(sqlChunks, sql.raw(' '));
```
```sql
select * from users where id = $1 or id = $2 or id = $3 or id = $4 or id = $5; --> [0, 1, 2, 3, 4]
```
</Section>

## sql.append()

If you have already generated SQL using the `sql` template, you can achieve the same behavior as `fromList`
by using the append function to directly add a new chunk to the generated SQL.

By using the append function, you can dynamically add additional SQL chunks to the existing SQL string,
effectively concatenating them together. This allows you to incorporate custom logic or business 
rules for aggregating the chunks into the final SQL query.

<Section>
```typescript 
const finalSql = sql`select * from users`;

// some logic

finalSql.append(sql` where `);

// some logic

for (let i = 0; i < 5; i++) {
	finalSql.append(sql`id = ${i}`);

	if (i === 4) continue;
	finalSql.append(sql` or `);
}
```
```sql
select * from users where id = $1 or id = $2 or id = $3 or id = $4 or id = $5; --> [0, 1, 2, 3, 4]
```
</Section>

## sql.empty()

By using sql.empty(), you can start with a blank SQL object and then dynamically append SQL chunks to it as needed. This allows you to construct the SQL query incrementally, applying custom logic or conditions to determine the contents of each chunk.

Once you have initialized the SQL object using sql.empty(), you can take advantage of the full range
of sql template features such as parameterization, composition, and escaping. 
This empowers you to construct the SQL query in a flexible and controlled manner, 
adapting it to your specific requirements.

```typescript 
const finalSql = sql.empty();

// some logic

finalSql.append(sql`select * from users`);

// some logic

finalSql.append(sql` where `);

// some logic

for (let i = 0; i < 5; i++) {
	finalSql.append(sql`id = ${i}`);

	if (i === 4) continue;
	finalSql.append(sql` or `);
}
```
```sql
select * from users where id = $1 or id = $2 or id = $3 or id = $4 or id = $5; --> [0, 1, 2, 3, 4]
```

## Convert `sql` to string and params

In all the previous examples, you observed the usage of SQL template syntax in TypeScript along with 
the generated SQL output.

If you need to obtain the query string and corresponding parameters generated from the SQL template, 
you must specify the database dialect you intend to generate the query for. Different databases have
varying syntax for parameterization and escaping, so selecting the appropriate dialect is crucial.

Once you have chosen the dialect, you can utilize the corresponding implementation's functionality
to convert the SQL template into the desired query string and parameter format. This ensures 
compatibility with the specific database system you are working with.

<Section>
```typescript copy
import { CockroachDialect } from 'drizzle-orm/cockroach-core';

const cockroachDialect = new CockroachDialect();
cockroachDialect.sqlToQuery(sql`select * from ${usersTable} where ${usersTable.id} = ${12}`);
```
```sql
select * from "users" where "users"."id" = $1; --> [ 12 ]
```
</Section>

## `sql` select

You can use the sql functionality in partial select queries as well. Partial select queries allow you to 
retrieve specific fields or columns from a table rather than fetching the entire row.

For more detailed information about partial select queries, you can refer to the Core API
documentation available at **[Core API docs](/docs/cockroach/select#basic-and-partial-select)**.

**Select different custom fields from table**

Here you can see a usage for **[`sql<T>`](/docs/cockroach/sql#sqlt)**, **[`sql``.mapWith()`](/docs/cockroach/sql#sqlmapwith)**, **[`sql``.as<T>()`](/docs/cockroach/sql#sqlast)**.

<Section>
```typescript copy
import { sql } from 'drizzle-orm'
import { usersTable } from './schema'

await db.select({
    id: usersTable.id,
    lowerName: sql<string>`lower(${usersTable.name})`,
    aliasedName: sql<string>`lower(${usersTable.name})`.as('aliased_column'),
    count: sql<number>`count(*)`.mapWith(Number) 
}).from(usersTable)
```
```sql
select "id", lower("name"), lower("name") as "aliased_column", count(*) from "users";
```
</Section>

## `sql` in where

Indeed, Drizzle provides a set of available expressions that you can use within the sql template. 
However, it is true that databases often have a wider range of expressions available, 
including those provided through extensions or other means.

To ensure flexibility and enable you to utilize any expressions that are not natively
supported by Drizzle, you have the freedom to write the SQL template
directly using the sql function. This allows you to leverage the full power of
SQL and incorporate any expressions or functionalities specific to your target database.

By using the sql template, you are not restricted to only the predefined expressions in Drizzle. 
Instead, you can express complex queries and incorporate any supported expressions that 
the underlying database system provides.

**Filtering by `id` but with sql**
<Section>
```typescript copy
import { sql } from 'drizzle-orm'
import { usersTable } from './schema'

const id = 77

await db.select()
        .from(usersTable)
        .where(sql`${usersTable.id} = ${id}`)
```
```sql
select * from "users" where "users"."id" = $1; --> [ 77 ]
```
</Section>

**Advanced fulltext search where statement**
<Section>
```typescript copy
import { sql } from 'drizzle-orm'
import { usersTable } from './schema'

const searchParam = "Ale"

await db.select()
        .from(usersTable)
        .where(sql`to_tsvector('simple', ${usersTable.name}) @@ to_tsquery('simple', ${searchParam})`)
```
```sql
select * from "users" where to_tsvector('simple', "users"."name") @@ to_tsquery('simple', '$1'); --> [ "Ale" ]
```
</Section>

## `sql` in orderBy

The `sql` template can indeed be used in the ORDER BY clause when you need specific functionality for ordering that is not
available in Drizzle, but you prefer not to resort to raw SQL.

<Section>
```typescript copy
import { sql } from 'drizzle-orm'
import { usersTable } from './schema'

await db.select().from(usersTable).orderBy(sql`${usersTable.id} desc nulls first`)
```
```sql
select * from "users" order by "users"."id" desc nulls first;
```
</Section>

## `sql` in having and groupBy

The `sql` template can indeed be used in the HAVING and GROUP BY clauses when you need specific functionality for ordering that is not
available in Drizzle, but you prefer not to resort to raw SQL.

<Section>
```typescript copy
import { sql } from 'drizzle-orm'
import { usersTable } from './schema'

await db.select({ 
    projectId: usersTable.projectId,
    count: sql<number>`count(${usersTable.id})`.mapWith(Number)
}).from(usersTable)
    .groupBy(sql`${usersTable.projectId}`)
    .having(sql`count(${usersTable.id}) > 300`)
```
```sql
select "project_id", count("id") from "users" group by "users"."project_id" having count("users"."id") > 300
```
</Section>


Source: https://orm.drizzle.team/docs/cockroach/transactions

# Transactions

SQL transaction is a grouping of one or more SQL statements that interact with a database.
A transaction in its entirety can commit to a database as a single logical unit
or rollback (become undone) as a single logical unit.

Drizzle ORM provides APIs to run SQL statements in transactions:

```ts copy
const db = drizzle(...)

await db.transaction(async (tx) => {
  await tx.update(accounts).set({ balance: sql`${accounts.balance} - 100.00` }).where(eq(users.name, 'Dan'));
  await tx.update(accounts).set({ balance: sql`${accounts.balance} + 100.00` }).where(eq(users.name, 'Andrew'));
});
```

Drizzle ORM supports `savepoints` with nested transactions API:

```ts copy {7-9}
const db = drizzle(...)

await db.transaction(async (tx) => {
  await tx.update(accounts).set({ balance: sql`${accounts.balance} - 100.00` }).where(eq(users.name, 'Dan'));
  await tx.update(accounts).set({ balance: sql`${accounts.balance} + 100.00` }).where(eq(users.name, 'Andrew'));

  await tx.transaction(async (tx2) => {
    await tx2.update(users).set({ name: "Mr. Dan" }).where(eq(users.name, "Dan"));
  });
});
```

You can embed business logic to the transaction and rollback whenever needed:

```ts copy {7}
const db = drizzle(...)

await db.transaction(async (tx) => {
  const [account] = await tx.select({ balance: accounts.balance }).from(accounts).where(eq(users.name, 'Dan'));
  if (account.balance < 100) {
    // This throws an exception that rollbacks the transaction.
    tx.rollback()
  }

  await tx.update(accounts).set({ balance: sql`${accounts.balance} - 100.00` }).where(eq(users.name, 'Dan'));
  await tx.update(accounts).set({ balance: sql`${accounts.balance} + 100.00` }).where(eq(users.name, 'Andrew'));
});
```

You can return values from the transaction:

```ts copy {8}
const db = drizzle(...)

const newBalance: number = await db.transaction(async (tx) => {
  await tx.update(accounts).set({ balance: sql`${accounts.balance} - 100.00` }).where(eq(users.name, 'Dan'));
  await tx.update(accounts).set({ balance: sql`${accounts.balance} + 100.00` }).where(eq(users.name, 'Andrew'));

  const [account] = await tx.select({ balance: accounts.balance }).from(accounts).where(eq(users.name, 'Dan'));
  return account.balance;
});
```

You can use transactions with **[relational queries](/docs/cockroach/rqb)**:

```ts
const db = drizzle({ schema })

await db.transaction(async (tx) => {
  await tx._query.users.findMany({
    with: {
      accounts: true
    }
  });
});
```

We provide dialect-specific transaction configuration APIs:

```ts copy {6-8}
await db.transaction(
  async (tx) => {
    await tx.update(accounts).set({ balance: sql`${accounts.balance} - 100.00` }).where(eq(users.name, "Dan"));
    await tx.update(accounts).set({ balance: sql`${accounts.balance} + 100.00` }).where(eq(users.name, "Andrew"));
  }, {
    isolationLevel: "read committed",
    accessMode: "read write",
    deferrable: true,
  }
);

interface CockroachTransactionConfig {
  isolationLevel?: 
    | "read uncommitted"
	| "read committed"
	| "repeatable read"
	| "serializable";
	accessMode?: "read only" | "read write";
	deferrable?: boolean;
}
```


Source: https://orm.drizzle.team/docs/cockroach/typebox-legacy

import Npm from '@mdx/Npm.astro';
import Callout from '@mdx/Callout.astro';

# typebox-legacy

### Install the dependencies
<Npm>
drizzle-orm@rc @sinclair/typebox
</Npm>

### Select schema

Defines the shape of data queried from the database - can be used to validate API responses.

```ts copy
import { int4, cockroachTable, text } from 'drizzle-orm/cockroach-core';
import { createSelectSchema } from 'drizzle-orm/typebox-legacy';
import { Value } from '@sinclair/typebox/value';

const users = cockroachTable('users', {
  id: int4().primaryKey().generatedAlwaysAsIdentity(),
  name: text().notNull(),
  age: int4().notNull()
});

const userSelectSchema = createSelectSchema(users);

const rows = await db.select({ id: users.id, name: users.name }).from(users).limit(1);
const parsed: { id: number; name: string; age: number } = Value.Parse(userSelectSchema, rows[0]); // Error: `age` is not returned in the above query

const rows = await db.select().from(users).limit(1);
const parsed: { id: number; name: string; age: number } = Value.Parse(userSelectSchema, rows[0]); // Will parse successfully
```

Views and enums are also supported.

```ts copy
import { cockroachEnum, cockroachView } from 'drizzle-orm/cockroach-core';
import { createSelectSchema } from 'drizzle-orm/typebox-legacy';
import { Value } from '@sinclair/typebox/value';

const roles = cockroachEnum('roles', ['admin', 'basic']);
const rolesSchema = createSelectSchema(roles);
const parsed: 'admin' | 'basic' = Value.Parse(rolesSchema, ...);

const usersView = cockroachView('users_view').as((qb) => qb.select().from(users).where(gt(users.age, 18)));
const usersViewSchema = createSelectSchema(usersView);
const parsed: { id: number; name: string; age: number } = Value.Parse(usersViewSchema, ...);
```

### Insert schema

Defines the shape of data to be inserted into the database - can be used to validate API requests.

```ts copy
import { int4, cockroachTable, text } from 'drizzle-orm/cockroach-core';
import { createInsertSchema } from 'drizzle-orm/typebox-legacy';
import { Value } from '@sinclair/typebox/value';

const users = cockroachTable('users', {
  id: int4().primaryKey().generatedAlwaysAsIdentity(),
  name: text().notNull(),
  age: int4().notNull()
});

const userInsertSchema = createInsertSchema(users);

const user = { name: 'John' };
const parsed: { name: string, age: number } = Value.Parse(userInsertSchema, user); // Error: `age` is not defined

const user = { name: 'Jane', age: 30 };
const parsed: { name: string, age: number } = Value.Parse(userInsertSchema, user); // Will parse successfully
await db.insert(users).values(parsed);
```

### Update schema

Defines the shape of data to be updated in the database - can be used to validate API requests.

```ts copy
import { int4, cockroachTable, text } from 'drizzle-orm/cockroach-core';
import { createUpdateSchema } from 'drizzle-orm/typebox-legacy';
import { Value } from '@sinclair/typebox/value';

const users = cockroachTable('users', {
  id: int4().primaryKey().generatedAlwaysAsIdentity(),
  name: text().notNull(),
  age: int4().notNull()
});

const userUpdateSchema = createUpdateSchema(users);

const user = { age: 35 };
const parsed: { name?: string | undefined, age?: number | undefined } = Value.Parse(userUpdateSchema, user); // Will parse successfully
await db.update(users).set(parsed).where(eq(users.name, 'Jane'));
```

### Refinements

Each create schema function accepts an additional optional parameter that you can used to extend, modify or completely overwite a field's schema. Defining a callback function will extend or modify while providing a Typebox schema will overwrite it.

```ts copy
import { int4, jsonb, cockroachTable, text } from 'drizzle-orm/cockroach-core';
import { createSelectSchema } from 'drizzle-orm/typebox-legacy';
import { Type } from '@sinclair/typebox';
import { Value } from '@sinclair/typebox/value';

const users = cockroachTable('users', {
  id: int4().primaryKey().generatedAlwaysAsIdentity(),
  name: text().notNull(),
  bio: text(),
  preferences: jsonb()
});

const userSelectSchema = createSelectSchema(users, {
  name: (schema) => Type.String({ ...schema, maxLength: 20 }), // Extends schema
  bio: (schema) => Type.String({ ...schema, maxLength: 1000 }), // Extends schema before becoming nullable/optional
  preferences: Type.Object({ theme: Type.String() }) // Overwrites the field, including its nullability
});

const parsed: {
  id: number;
  name: string,
  bio: string | null;
  preferences: {
    theme: string;
  };
} = Value.Parse(userSelectSchema, ...);
```

### Factory functions

For more advanced use cases, you can use the `createSchemaFactory` function.

**Use case: Using an extended Typebox instance**

```ts copy
import { int4, cockroachTable, text } from 'drizzle-orm/cockroach-core';
import { createSchemaFactory } from 'drizzle-orm/typebox';
import { t } from 'elysia'; // Extended Typebox instance

const users = cockroachTable('users', {
  id: int4().primaryKey().generatedAlwaysAsIdentity(),
  name: text().notNull(),
  age: int4().notNull()
});

const { createInsertSchema } = createSchemaFactory({ typeboxInstance: t });

const userInsertSchema = createInsertSchema(users, {
  // We can now use the extended instance
  name: (schema) => t.Number({ ...schema }, { error: '`name` must be a string' })
});
```

### Data type reference

CockroachDB data type mappings follow the CockroachDB column builders. See the [CockroachDB data types](/docs/cockroach/column-types) page for the full column reference.


Source: https://orm.drizzle.team/docs/cockroach/typebox

import Npm from '@mdx/Npm.astro';
import Callout from '@mdx/Callout.astro';

# typebox

#### Install the dependencies
<Npm>
drizzle-orm@rc typebox
</Npm>

Allows you to generate [typebox](https://sinclairzx81.github.io/typebox/#/) schemas from Drizzle ORM schemas

**Features**

- Create a select schema for tables and enums.
- Create insert and update schemas for tables.
- Supported dialect: CockroachDB.

#### Usage

```ts
import { int4, cockroachTable, text, timestamp } from 'drizzle-orm/cockroach-core';
import { createInsertSchema, createSelectSchema, createUpdateSchema } from 'drizzle-orm/typebox';
import { Type } from 'typebox';
import { Value } from 'typebox/value';

const users = cockroachTable('users', {
	id: int4().primaryKey().generatedAlwaysAsIdentity(),
	name: text().notNull(),
	email: text().notNull(),
	role: text({ enum: ['admin', 'user'] }).notNull(),
	createdAt: timestamp('created_at').notNull().defaultNow(),
});

// Schema for inserting a user - can be used to validate API requests
const insertUserSchema = createInsertSchema(users);

// Schema for updating a user - can be used to validate API requests
const updateUserSchema = createUpdateSchema(users);

// Schema for selecting a user - can be used to validate API responses
const selectUserSchema = createSelectSchema(users);

// Overriding the fields
const insertUserSchema = createInsertSchema(users, {
	role: Type.String(),
});

// Refining the fields - useful if you want to change the fields before they become nullable/optional in the final schema
const insertUserSchema = createInsertSchema(users, {
	id: (schema) => Type.Number({ ...schema, minimum: 0 }),
	role: Type.String(),
});

// Usage

const isUserValid: boolean = Value.Check(insertUserSchema, {
	name: 'John Doe',
	email: 'johndoe@test.com',
	role: 'admin',
});
```


Source: https://orm.drizzle.team/docs/cockroach/update

import Callout from '@mdx/Callout.astro';
import Section from '@mdx/Section.astro';

# SQL Update

<Callout type='info'>
All the values provided to `.set()`are parameterized automatically.
For example, this query:
```ts
await db.update(users).set({ name: "Mr. Dan" }).where(eq(users.name, "Dan"));
```
will be translated to:
```sql
update "users" set "name" = $1 where "users"."name" = $2; -- params: ['Mr. Dan', 'Dan']
```
</Callout>

<br/>

The object that you pass to `update` should have keys that match column names in your database schema.
Values of `undefined` are ignored in the object: to set a column to `null`, pass `null`.

```typescript copy
await db.update(users)
  .set({ name: 'Mr. Dan' })
  .where(eq(users.name, 'Dan'));
```
```typescript copy
await db.update(users)
  .set({ name: null })
  .where(eq(users.name, 'Dan'));
```

You can pass SQL as a value to be used in the update object, like this:

```typescript copy
await db.update(users)
  .set({ updatedAt: sql`NOW()` })
  .where(eq(users.name, 'Dan'));
```

### Returning

You can update a row and get it back in CockroachDB:
```typescript copy
const updatedUserId = await db.update(users).set({ name: "Mr. Dan" }).where(eq(users.name, "Dan")).returning({ updatedId: users.id });
//      ^ { updatedId: number | null }[]
```
```sql
update "users" set "name" = 'Mr. Dan' where "users"."name" = 'Dan' returning "id";
```

## `with update` clause

<Callout>
  Check how to use WITH statement with [select](/docs/cockroach/select#with-clause), [insert](/docs/cockroach/insert#with-insert-clause), [delete](/docs/cockroach/delete#with-delete-clause)
</Callout>

Using the `with` clause can help you simplify complex queries by splitting them into smaller subqueries called common table expressions (CTEs):
<Section>
```typescript copy
const averagePrice = db.$with('average_price').as(
	db.select({ value: sql`avg(${products.price})`.as('value') }).from(products)
);

const result = await db.with(averagePrice)
	.update(products)
	.set({
		cheap: true
	})
	.where(lt(products.price, sql`(select * from ${averagePrice})`))
	.returning({
		id: products.id
	});
```
```sql
with "average_price" as (select avg("price") as "value" from "products") 
update "products" set "cheap" = true 
where "products"."price" < (select * from "average_price") 
returning "id"
```
</Section>

## Update ... from

As CockroachDB documentation states:

> A table expression allowing columns from other tables to appear in the WHERE condition and update expressions

<Section>
```ts
await db
  .update(users)
  .set({ cityId: cities.id })
  .from(cities)
  .where(and(eq(cities.name, 'Seattle'), eq(users.name, 'John')))
```
```sql
update "users" set "city_id" = "cities"."id" 
from "cities" 
where (("cities"."name" = 'Seattle') and ("users"."name" = 'John'))
```
</Section>

You can also alias tables that are joined (you can also alias the updating table too).
<Section>
```ts
const c = alias(cities, 'c');
await db
  .update(users)
  .set({ cityId: c.id })
  .from(c);
```
```sql
update "users" set "city_id" = "c"."id" 
from "cities" "c"
```
</Section>

In Postgres, you can also return columns from the joined tables.
<Section>
```ts
const updatedUsers = await db
  .update(users)
  .set({ cityId: cities.id })
  .from(cities)
  .returning({ id: users.id, cityName: cities.name });
```
```sql
update "users" set "city_id" = "cities"."id" 
from "cities" 
returning "users"."id", "cities"."name"
```
</Section>


Source: https://orm.drizzle.team/docs/cockroach/valibot

import Npm from '@mdx/Npm.astro';
import Callout from '@mdx/Callout.astro';

# valibot

### Install the dependencies

<Npm>
drizzle-orm@rc valibot
</Npm>

### Select schema

Defines the shape of data queried from the database - can be used to validate API responses.

```ts copy
import { int4, cockroachTable, text } from 'drizzle-orm/cockroach-core';
import { createSelectSchema } from 'drizzle-orm/valibot';
import { parse } from 'valibot';

const users = cockroachTable('users', {
  id: int4().primaryKey().generatedAlwaysAsIdentity(),
  name: text().notNull(),
  age: int4().notNull()
});

const userSelectSchema = createSelectSchema(users);

const rows = await db.select({ id: users.id, name: users.name }).from(users).limit(1);
const parsed: { id: number; name: string; age: number } = parse(userSelectSchema, rows[0]); // Error: `age` is not returned in the above query

const rows = await db.select().from(users).limit(1);
const parsed: { id: number; name: string; age: number } = parse(userSelectSchema, rows[0]); // Will parse successfully
```

Views and enums are also supported.

```ts copy
import { cockroachEnum, cockroachView } from 'drizzle-orm/cockroach-core';
import { createSelectSchema } from 'drizzle-orm/valibot';
import { parse } from 'valibot';

const roles = cockroachEnum('roles', ['admin', 'basic']);
const rolesSchema = createSelectSchema(roles);
const parsed: 'admin' | 'basic' = parse(rolesSchema, ...);

const usersView = cockroachView('users_view').as((qb) => qb.select().from(users).where(gt(users.age, 18)));
const usersViewSchema = createSelectSchema(usersView);
const parsed: { id: number; name: string; age: number } = parse(usersViewSchema, ...);
```

### Insert schema

Defines the shape of data to be inserted into the database - can be used to validate API requests.

```ts copy
import { int4, cockroachTable, text } from 'drizzle-orm/cockroach-core';
import { createInsertSchema } from 'drizzle-orm/valibot';
import { parse } from 'valibot';

const users = cockroachTable('users', {
  id: int4().primaryKey().generatedAlwaysAsIdentity(),
  name: text().notNull(),
  age: int4().notNull()
});

const userInsertSchema = createInsertSchema(users);

const user = { name: 'John' };
const parsed: { name: string, age: number } = parse(userInsertSchema, user); // Error: `age` is not defined

const user = { name: 'Jane', age: 30 };
const parsed: { name: string, age: number } = parse(userInsertSchema, user); // Will parse successfully
await db.insert(users).values(parsed);
```

### Update schema

Defines the shape of data to be updated in the database - can be used to validate API requests.

```ts copy
import { int4, cockroachTable, text } from 'drizzle-orm/cockroach-core';
import { createUpdateSchema } from 'drizzle-orm/valibot';
import { parse } from 'valibot';

const users = cockroachTable('users', {
  id: int4().primaryKey().generatedAlwaysAsIdentity(),
  name: text().notNull(),
  age: int4().notNull()
});

const userUpdateSchema = createUpdateSchema(users);

const user = { age: 35 };
const parsed: { name?: string | undefined, age?: number | undefined } = parse(userUpdateSchema, user); // Will parse successfully
await db.update(users).set(parsed).where(eq(users.name, 'Jane'));
```

### Refinements

Each create schema function accepts an additional optional parameter that you can used to extend, modify or completely overwite a field's schema. Defining a callback function will extend or modify while providing a Valibot schema will overwrite it.

```ts copy
import { int4, jsonb, cockroachTable, text } from 'drizzle-orm/cockroach-core';
import { createSelectSchema } from 'drizzle-orm/valibot';
import { parse, pipe, maxLength, object, string } from 'valibot';

const users = cockroachTable('users', {
  id: int4().primaryKey().generatedAlwaysAsIdentity(),
  name: text().notNull(),
  bio: text(),
  preferences: jsonb()
});

const userSelectSchema = createSelectSchema(users, {
  name: (schema) => pipe(schema, maxLength(20)), // Extends schema
  bio: (schema) => pipe(schema, maxLength(1000)), // Extends schema before becoming nullable/optional
  preferences: object({ theme: string() }) // Overwrites the field, including its nullability
});

const parsed: {
  id: number;
  name: string,
  bio: string | null;
  preferences: {
    theme: string;
  };
} = parse(userSelectSchema, ...);
```

### Data type reference

CockroachDB data type mappings follow the CockroachDB column builders. See the [CockroachDB data types](/docs/cockroach/column-types) page for the full column reference.


Source: https://orm.drizzle.team/docs/cockroach/views

import Callout from '@mdx/Callout.astro';
import Section from '@mdx/Section.astro';

# Views

There're several ways you can declare views with Drizzle ORM.  

You can declare views that have to be created or you can declare views that already exist in the database. 

You can declare views statements with an inline `query builder` syntax, with `standalone query builder` and with raw `sql` operators. 

When views are created with either inlined or standalone query builders, view columns schema will be automatically inferred, 
yet when you use `sql` you have to explicitly declare view columns schema.

### Declaring views

<Section>
      ```ts filename="schema.ts" copy {14-15}
      import { cockroachTable, cockroachView, int4, text, timestamp } from "drizzle-orm/cockroach-core";
      import { eq } from "drizzle-orm";

      export const user = cockroachTable("user", {
        id: int4(),
        name: text(),
        email: text(),
        password: text(),
        role: text().$type<"admin" | "customer">(),
        createdAt: timestamp("created_at"),
        updatedAt: timestamp("updated_at"),
      });

      export const userView = cockroachView("user_view").as((qb) => qb.select().from(user));
      export const customersView = cockroachView("customers_view").as((qb) => qb.select().from(user).where(eq(user.role, "customer")));
      ```
      ```sql
      CREATE VIEW "customers_view" AS (select ... from "user" where "user"."role" = 'customer');
      CREATE VIEW "user_view" AS (select ... from "user");
      ```
    </Section>

You can also declare views using `standalone query builder`, it works exactly the same way:

<Section>
      ```ts filename="schema.ts" copy {4,16-17}
      import { cockroachTable, cockroachView, int4, text, timestamp, QueryBuilder} from "drizzle-orm/cockroach-core";
      import { eq } from "drizzle-orm";

      const qb = new QueryBuilder();

      export const user = cockroachTable("user", {
        id: int4(),
        name: text(),
        email: text(),
        password: text(),
        role: text().$type<"admin" | "customer">(),
        createdAt: timestamp("created_at"),
        updatedAt: timestamp("updated_at"),
      });

      export const userView = cockroachView("user_view").as(qb.select().from(user));
      export const customersView = cockroachView("customers_view").as(qb.select().from(user).where(eq(user.role, "customer")));
      ```
      ```sql
      CREATE VIEW "user_view" AS (SELECT ... FROM "user");
      CREATE VIEW "customers_view" AS (SELECT ... FROM "user" WHERE "user"."role" = 'customer');
      ```
    </Section>

### Declaring views with raw SQL
Whenever you need to declare view using a syntax that is not supported by the query builder, 
you can directly use `sql` operator and explicitly specify view columns schema.

```ts copy
// regular view
export const newYorkers = cockroachView('new_yorkers', {
  id: int4().primaryKey(),
  name: text().notNull(),
  cityId: integer('city_id').notNull(),
}).as(sql`select * from ${users} where ${eq(users.cityId, 1)}`);

// materialized view
export const newYorkers = cockroachMaterializedView('new_yorkers', {
  id: int4().primaryKey(),
  name: text().notNull(),
  cityId: integer('city_id').notNull(),
}).as(sql`select * from ${users} where ${eq(users.cityId, 1)}`);
```

### Declaring existing views
When you're provided with a read only access to an existing view in the database you should use `.existing()` view configuration, 
`drizzle-kit` will ignore and will not generate a `create view` statement in the generated migration.
```ts {16,23}
export const user = cockroachTable("user", {
  id: int4(),
  name: text(),
  email: text(),
  password: text(),
  role: text().$type<"admin" | "customer">(),
  createdAt: timestamp("created_at"),
  updatedAt: timestamp("updated_at"),
});

// regular view
export const trimmedUser = cockroachView("trimmed_user", {
  id: int4("id"),
  name: text("name"),
  email: text("email"),
}).existing();

// materialized view won't make any difference, yet you can use it for consistency
export const trimmedUser = cockroachMaterializedView("trimmed_user", {
  id: int4("id"),
  name: text("name"),
  email: text("email"),
}).existing();
```

### Materialized views

According to the official docs, CockroachDB have both **[`regular`](https://www.cockroachlabs.com/docs/v26.2/create-view.html#synopsis)**
and **[`materialized`](https://www.cockroachlabs.com/docs/v26.2/create-view.html#synopsis)** views.
  
Materialized views in CockroachDB use the rule system like views do, but persist the results in a table-like form.
{/* This means that when a query is executed against a materialized view, the results are returned directly from the materialized view,
like from a table, rather than being reconstructed by executing the query against the underlying base tables that make up the view. */}

<Section>
```ts filename="schema.ts" copy
export const newYorkers = cockroachMaterializedView('new_yorkers').as((qb) => qb.select().from(users).where(eq(users.cityId, 1)));
```
```sql
CREATE MATERIALIZED VIEW "new_yorkers" AS (SELECT ... FROM "users" WHERE "users"."city_id" = 1);
```
</Section>

You can then refresh materialized views in the application runtime:
```ts copy
await db.refreshMaterializedView(newYorkers);

await db.refreshMaterializedView(newYorkers).concurrently();

await db.refreshMaterializedView(newYorkers).withNoData();
```

### Extended example
<Callout type="info" emoji="ℹ️">
All the parameters inside the query will be inlined, instead of replaced by `$1`, `$2`, etc.
</Callout>

```ts copy
export const newYorkers = cockroachView('new_yorkers').as((qb) => {
  const sq = qb.$with('sq').as(
    qb
      .select({
        userId: users.id.as('users_id'),
        cityId: cities.id.as('cities_id'),
        homeCity: users.homeCity,
      })
      .from(users)
      .leftJoin(cities, eq(cities.id, users.homeCity))
      .where(sql`${users.age1} > 18`),
  );
  return qb
    .with(sq)
    .select()
    .from(sq)
    .where(sql`${sq.homeCity} = 1`);
});

// materialized view
export const newYorkers2 = cockroachMaterializedView('new_yorkers_2')
  .withNoData()
  .as((qb) => {
    const sq = qb.$with('sq').as(
      qb
        .select({
          userId: users.id.as('users_id'),
          cityId: cities.id.as('cities_id'),
          homeCity: users.homeCity,
        })
        .from(users)
        .leftJoin(cities, eq(cities.id, users.homeCity))
        .where(sql`${users.age1} > 18`),
    );
    return qb
      .with(sq)
      .select()
      .from(sq)
      .where(sql`${sq.homeCity} = 1`);
  });
```
```sql
...

CREATE VIEW "new_yorkers" AS (
	WITH
		"sq" AS (
			SELECT
				"users"."id" AS "users_id",
				"cities"."id" AS "cities_id",
				"users"."home_city"
			FROM
				"users"
				LEFT JOIN "cities" ON "cities"."id" = "users"."home_city"
			WHERE
				"users"."age" > 18
		)
	SELECT
		"users_id",
		"cities_id",
		"home_city"
	FROM
		"sq"
	WHERE
		"sq"."home_city" = 1
);

CREATE MATERIALIZED VIEW "new_yorkers_2" AS (
	WITH
		"sq" AS (
			SELECT
				"users"."id" AS "users_id",
				"cities"."id" AS "cities_id",
				"users"."home_city"
			FROM
				"users"
				LEFT JOIN "cities" ON "cities"."id" = "users"."home_city"
			WHERE
				"users"."age" > 18
		)
	SELECT
		"users_id",
		"cities_id",
		"home_city"
	FROM
		"sq"
	WHERE
		"sq"."home_city" = 1
)
WITH
	NO DATA;
```


Source: https://orm.drizzle.team/docs/cockroach/zod

import Npm from '@mdx/Npm.astro';
import Callout from '@mdx/Callout.astro';

# zod

### Install the dependencies

<Npm>
drizzle-orm@rc zod
</Npm>

### Select schema

Defines the shape of data queried from the database - can be used to validate API responses.

```ts copy
import { int4, cockroachTable, text } from 'drizzle-orm/cockroach-core';
import { createSelectSchema } from 'drizzle-orm/zod';

const users = cockroachTable('users', {
  id: int4().primaryKey().generatedAlwaysAsIdentity(),
  name: text().notNull(),
  age: int4().notNull()
});

const userSelectSchema = createSelectSchema(users);

const rows = await db.select({ id: users.id, name: users.name }).from(users).limit(1);
const parsed: { id: number; name: string; age: number } = userSelectSchema.parse(rows[0]); // Error: `age` is not returned in the above query

const rows = await db.select().from(users).limit(1);
const parsed: { id: number; name: string; age: number } = userSelectSchema.parse(rows[0]); // Will parse successfully
```

Enums are also supported.

```ts copy
import { cockroachEnum } from 'drizzle-orm/cockroach-core';
import { createSelectSchema } from 'drizzle-orm/zod';

const roles = cockroachEnum('roles', ['admin', 'basic']);
const rolesSchema = createSelectSchema(roles);
const parsed: 'admin' | 'basic' = rolesSchema.parse(...);
```

### Insert schema

Defines the shape of data to be inserted into the database - can be used to validate API requests.

```ts copy
import { int4, cockroachTable, text } from 'drizzle-orm/cockroach-core';
import { createInsertSchema } from 'drizzle-orm/zod';

const users = cockroachTable('users', {
  id: int4().primaryKey().generatedAlwaysAsIdentity(),
  name: text().notNull(),
  age: int4().notNull()
});

const userInsertSchema = createInsertSchema(users);

const user = { name: 'John' };
const parsed: { name: string, age: number } = userInsertSchema.parse(user); // Error: `age` is not defined

const user = { name: 'Jane', age: 30 };
const parsed: { name: string, age: number } = userInsertSchema.parse(user); // Will parse successfully
await db.insert(users).values(parsed);
```

### Update schema

Defines the shape of data to be updated in the database - can be used to validate API requests.

```ts copy
import { int4, cockroachTable, text } from 'drizzle-orm/cockroach-core';
import { createUpdateSchema } from 'drizzle-orm/zod';

const users = cockroachTable('users', {
  id: int4().primaryKey().generatedAlwaysAsIdentity(),
  name: text().notNull(),
  age: int4().notNull()
});

const userUpdateSchema = createUpdateSchema(users);

const user = { age: 35 };
const parsed: { name?: string | undefined, age?: number | undefined } = userUpdateSchema.parse(user); // Will parse successfully
await db.update(users).set(parsed).where(eq(users.name, 'Jane'));
```

### Refinements

Each create schema function accepts an additional optional parameter that you can used to extend, modify or completely overwite a field's schema. Defining a callback function will extend or modify while providing a Zod schema will overwrite it.

```ts copy
import { int4, jsonb, cockroachTable, text } from 'drizzle-orm/cockroach-core';
import { createSelectSchema } from 'drizzle-orm/zod';
import { z } from 'zod/v4';

const users = cockroachTable('users', {
  id: int4().primaryKey(),
  name: text().notNull(),
  bio: text(),
  preferences: jsonb()
});

const userSelectSchema = createSelectSchema(users, {
  name: (schema) => schema.max(20), // Extends schema
  bio: (schema) => schema.max(1000), // Extends schema before becoming nullable/optional
  preferences: z.object({ theme: z.string() }) // Overwrites the field, including its nullability
});

const parsed: {
  id: number;
  name: string,
  bio: string | null;
  preferences: {
    theme: string;
  };
} = userSelectSchema.parse(...);
```

### Factory functions

For more advanced use cases, you can use the `createSchemaFactory` function.

**Use case: Using an extended Zod instance**

```ts copy
import { int4, cockroachTable, text } from 'drizzle-orm/cockroach-core';
import { createSchemaFactory } from 'drizzle-orm/zod';
import { z } from '@hono/zod-openapi'; // Extended Zod instance

const users = cockroachTable('users', {
  id: int4().primaryKey().generatedAlwaysAsIdentity(),
  name: text().notNull(),
  age: int4().notNull()
});

const { createInsertSchema } = createSchemaFactory({ zodInstance: z });

const userInsertSchema = createInsertSchema(users, {
  // We can now use the extended instance
  name: (schema) => schema.openapi({ example: 'John' })
});
```

**Use case: Type coercion**

```ts copy
import { cockroachTable, timestamp } from 'drizzle-orm/cockroach-core';
import { createSchemaFactory } from 'drizzle-orm/zod';
import { z } from 'zod/v4';

const users = cockroachTable('users', {
  ...,
  createdAt: timestamp().notNull()
});

const { createInsertSchema } = createSchemaFactory({
  // This configuration will only coerce dates. Set `coerce` to `true` to coerce all data types or specify others
  coerce: {
    date: true
  }
});

const userInsertSchema = createInsertSchema(users);
// The above is the same as this:
const userInsertSchema = z.object({
  ...,
  createdAt: z.coerce.date()
});
```

### Data type reference

CockroachDB data type mappings follow the CockroachDB column builders. See the [CockroachDB data types](/docs/cockroach/column-types) page for the full column reference.


Source: https://orm.drizzle.team/docs/column-types/cockroach


import Section from '@mdx/Section.astro';
import Callout from '@mdx/Callout.astro';
import Npm from '@mdx/Npm.astro';

<Callout type='error'>
This page explains concepts available on drizzle versions `1.0.0-beta.2` and higher.
</Callout>

<Npm>
drizzle-orm@rc
drizzle-kit@rc -D
</Npm>

<br/>

We have native support for all of them, yet if that's not enough for you, feel free to create **[custom types](/docs/custom-types)**.

<Callout title='important' type='warning'>
All examples in this part of the documentation do not use database column name aliases, and column names are generated from TypeScript keys. 

You can use database aliases in column names if you want, and you can also use the `casing` parameter to define a mapping strategy for Drizzle. 

You can read more about it [here](/docs/sql-schema-declaration#shape-your-data-schema)
</Callout>

### bigint
`int` `int8` `int64` `integer`

Signed 8-byte integer     

If you're expecting values above 2^31 but below 2^53, you can utilize `mode: 'number'` and deal with javascript number as opposed to bigint.
<Section>
```typescript
import { bigint, cockroachTable } from "drizzle-orm/cockroach-core";

export const table = cockroachTable('table', {
	bigint: bigint({ mode: 'number' })
});

// will be inferred as `number`
bigint: bigint({ mode: 'number' })

// will be inferred as `bigint`
bigint: bigint({ mode: 'bigint' })
```

```sql
CREATE TABLE "table" (
	"bigint" bigint
);
```
</Section>

<Section>
```typescript
import { sql } from "drizzle-orm";
import { bigint, cockroachTable } from "drizzle-orm/cockroach-core";

export const table = cockroachTable('table', {
	bigint1: bigint().default(10),
	bigint2: bigint().default(sql`'10'::bigint`)
});
```

```sql
CREATE TABLE "table" (
	"bigint1" bigint DEFAULT 10,
	"bigint2" bigint DEFAULT '10'::bigint
);
```
</Section>

### smallint
`smallint` `int2`  
Small-range signed 2-byte integer   

<Section>
```typescript
import { smallint, cockroachTable } from "drizzle-orm/cockroach-core";

export const table = cockroachTable('table', {
	smallint: smallint()
});
```

```sql
CREATE TABLE "table" (
	"smallint" smallint
);
```
</Section>

<Section>
```typescript
import { sql } from "drizzle-orm";
import { smallint, cockroachTable } from "drizzle-orm/cockroach-core";

export const table = cockroachTable('table', {
	smallint1: smallint().default(10),
	smallint2: smallint().default(sql`'10'::smallint`)
});
```

```sql
CREATE TABLE "table" (
	"smallint1" smallint DEFAULT 10,
	"smallint2" smallint DEFAULT '10'::smallint
);
```
</Section>

### int4

Signed 4-byte integer     

<Section>
```typescript
import { int4, cockroachTable } from "drizzle-orm/cockroach-core";

export const table = cockroachTable('table', {
	int4: int4()
});

```

```sql
CREATE TABLE "table" (
	"int4" int4
);
```
</Section>

<Section>
```typescript
import { sql } from "drizzle-orm";
import { int4, cockroachTable } from "drizzle-orm/cockroach-core";

export const table = cockroachTable('table', {
	int1: int4().default(10),
	int2: int4().default(sql`'10'::int4`)
});
```

```sql
CREATE TABLE "table" (
	"int1" int4 DEFAULT 10,
	"int2" int4 DEFAULT '10'::int4
);
```
</Section>


### int8

An alias of **[bigint.](#bigint)**

### int2

An alias of **[smallint.](#smallint)**

### ---

### bool
Cockroach provides the standard SQL type bool.

For more info please refer to the official Cockroach **[docs.](https://www.cockroachlabs.com/docs/stable/bool)**

<Section>
```typescript
import { bool, cockroachTable } from "drizzle-orm/cockroach-core";

export const table = cockroachTable('table', {
	boolean: bool()
});

```

```sql
CREATE TABLE "table" (
	"boolean" bool
);
```
</Section>

## ---

### string
`text` `varchar`, `char`

The `STRING` data type stores a string of Unicode characters.

<Callout>
For PostgreSQL compatibility, CockroachDB supports the following STRING-related types and their aliases:

`VARCHAR` (and alias `CHARACTER VARYING`)
`CHAR` (and alias `CHARACTER`)
`NAME`
</Callout>

For more info please refer to the official CockroachDB **[docs.](https://www.cockroachlabs.com/docs/stable/string)**
  
You can define `{ enum: ["value1", "value2"] }` config to infer `insert` and `select` types, it **won't** check runtime values.
<Section>
```typescript
import { string, cockroachTable } from "drizzle-orm/cockroach-core";

export const table = cockroachTable('table', {
  stringColumn: string(), // equivalent to `text` PostgreSQL type
  stringColumn1: string({ length: 256 }), // equivalent to `varchar(256)` PostgreSQL type
});

// will be inferred as text: "value1" | "value2" | null
stringColumn: string({ enum: ["value1", "value2"] })
```

```sql
CREATE TABLE "table" (
	"stringColumn" string,
    "stringColumn1" string(256),
);
```
</Section>

### text

CockroachDB alias for `STRING`:

For more info please refer to the official CockroachDB **[docs.](https://www.cockroachlabs.com/docs/stable/string)**
  
You can define `{ enum: ["value1", "value2"] }` config to infer `insert` and `select` types, it **won't** check runtime values.
<Section>
```typescript
import { text, cockroachTable } from "drizzle-orm/cockroach-core";

export const table = cockroachTable('table', {
  text: text()
});

// will be inferred as text: "value1" | "value2" | null
text: text({ enum: ["value1", "value2"] })
```

```sql
CREATE TABLE "table" (
	"text" text
);
```
</Section>

### varchar
`character varying(n)` `varchar(n)`  

`STRING` alias used to stay compatible with PostgreSQL

For more info please refer to the official CockroachDB **[docs.](https://www.cockroachlabs.com/docs/stable/string)**

You can define `{ enum: ["value1", "value2"] }` config to infer `insert` and `select` types, it **won't** check runtime values.

The `length` parameter is optional according to PostgreSQL docs.
<Section>
```typescript
import { varchar, cockroachTable } from "drizzle-orm/cockroach-core";

export const table = cockroachTable('table', {
  varchar1: varchar(),
  varchar2: varchar({ length: 256 }),
});

// will be inferred as text: "value1" | "value2" | null
varchar: varchar({ enum: ["value1", "value2"] }),
```

```sql
CREATE TABLE "table" (
	"varchar1" varchar,
	"varchar2" varchar(256)
);
```
</Section>

### char
`character(n)` `char(n)`  

`STRING` alias used to stay compatible with PostgreSQL

For more info please refer to the official CockroachDB **[docs.](https://www.cockroachlabs.com/docs/stable/string)**

You can define `{ enum: ["value1", "value2"] }` config to infer `insert` and `select` types, it **won't** check runtime values.

The `length` parameter is optional according to PostgreSQL docs.
<Section>
```typescript
import { char, cockroachTable } from "drizzle-orm/cockroach-core";

export const table = cockroachTable('table', {
  char1: char(),
  char2: char({ length: 256 }),
});

// will be inferred as text: "value1" | "value2" | null
char: char({ enum: ["value1", "value2"] }),
```

```sql
CREATE TABLE "table" (
	"char1" char,
	"char2" char(256)
);
```
</Section>

## ---

https://www.cockroachlabs.com/docs/stable/float

### decimal

`numeric` `decimal` `dec`
The DECIMAL data type stores exact, fixed-point numbers. This type is used when it is important to preserve exact precision, for example, with monetary data.

For more info please refer to the official CockroachDB **[docs.](https://www.cockroachlabs.com/docs/stable/decimal)**

<Section>
```typescript
import { decimal, cockroachTable } from "drizzle-orm/cockroach-core";

export const table = cockroachTable('table', {
  decimal1: decimal(),
  decimal2: decimal({ precision: 100 }),
  decimal3: decimal({ precision: 100, scale: 20 }),
  decimalNum: decimal({ mode: 'number' }),
  decimalBig: decimal({ mode: 'bigint' }),
});
```

```sql
CREATE TABLE "table" (
	"decimal1" decimal,
	"decimal2" decimal(100),
	"decimal3" decimal(100, 20),
	"decimalNum" decimal,
	"decimalBig" decimal
);
```
</Section>

### numeric
An alias of **[decimal.](#decimal)**

### float
`float` `float8` `double precision`  

For more info please refer to the official CockroachDB **[docs.](https://www.cockroachlabs.com/docs/stable/float)**  

<Section>
```typescript
import { sql } from "drizzle-orm";
import { float, cockroachTable } from "drizzle-orm/cockroach-core";  

const table = cockroachTable('table', {
	float1: float(),
	float2: float().default(10.10),
	float3: float().default(sql`'10.10'::float`),
});
```

```sql
CREATE TABLE "table" (
	"float1" float,
	"float2" float default 10.10,
	"float3" float default '10.10'::float
);
```
</Section>

### real
`real` `float4`  
Single precision floating-point number (4 bytes)

For more info please refer to the official CockroachDB **[docs.](https://www.cockroachlabs.com/docs/stable/float)**  

<Section>
```typescript
import { sql } from "drizzle-orm";
import { real, cockroachTable } from "drizzle-orm/cockroach-core";  

const table = cockroachTable('table', {
	real1: real(),
	real2: real().default(10.10),
	real3: real().default(sql`'10.10'::real`),
});
```

```sql
CREATE TABLE "table" (
	"real1" real,
	"real2" real default 10.10,
	"real3" real default '10.10'::real
);
```
</Section>

### double precision

An alias of **[float.](#float)**

## ---

### jsonb
`jsonb`  

The JSONB data type stores JSON (JavaScript Object Notation) data as a binary representation of the JSONB value, which eliminates whitespace, duplicate keys, and key ordering

For more info please refer to the official CockroachDB **[docs.](https://www.cockroachlabs.com/docs/stable/jsonb)**
<Section>
```typescript
import { jsonb, cockroachTable } from "drizzle-orm/cockroach-core";

const table = cockroachTable('table', {
	jsonb1: jsonb(),
	jsonb2: jsonb().default({ foo: "bar" }),
	jsonb3: jsonb().default(sql`'{foo: "bar"}'::jsonb`),
});
```
```sql
CREATE TABLE "table" (
	"jsonb1" jsonb,
	"jsonb2" jsonb default '{"foo": "bar"}'::jsonb,
	"jsonb3" jsonb default '{"foo": "bar"}'::jsonb
);
```
</Section>

You can specify `.$type<..>()` for json object inference, it **won't** check runtime values. 
It provides compile time protection for default values, insert and select schemas.

```typescript
// will be inferred as { foo: string }
jsonb: jsonb().$type<{ foo: string }>();

// will be inferred as string[]
jsonb: jsonb().$type<string[]>();

// won't compile
jsonb: jsonb().$type<string[]>().default({});
```

## ---

### bit
`bit`  

The BIT data types store bit arrays. With BIT, the length is fixed.

<br />

**Size**

The number of bits in a BIT value is determined as follows:

| Type&nbsp;declaration		| Logical&nbsp;size	|
|:------------------		|:--------------	|
| BIT						| 1 bit				|
| BIT(N)					| N bits			|

<br />

For more info please refer to the official CockroachDB **[docs.](https://www.cockroachlabs.com/docs/stable/bit)**
<Section>
```typescript
import { sql } from "drizzle-orm";
import { cockroachTable, bit } from "drizzle-orm/cockroach-core";

export const table = cockroachTable('table', {
	bit1: bit(),
	bit2: bit({ length: 15 }),
	bit3: bit({ length: 15 }).default('10011'),
	bit4: bit({ length: 15 }).default(sql`'10011'`)
});
```
```sql
CREATE TABLE "table" (
	"bit1" bit,
	"bit2" bit(15),
	"bit3" bit(15) DEFAULT '10011',
	"bit4" bit(15) DEFAULT '10011'
);

```
</Section>

### varbit
`varbit`

The VARBIT data types store bit arrays. With VARBIT, the length can be variable.

<br />

**Size**

The number of bits in a VARBIT value is determined as follows:

| Type&nbsp;declaration		| Logical&nbsp;size													|
|:------------------		|:--------------													|
| VARBIT					| variable&nbsp;with&nbsp;no&nbsp;maximum							|
| VARBIT(N)					| variable&nbsp;with&nbsp;a&nbsp;maximum&nbsp;of&nbsp;N&nbsp;bits	|

<br />

For more info please refer to the official CockroachDB **[docs.](https://www.cockroachlabs.com/docs/stable/bit)**
<Section>
```typescript
import { sql } from "drizzle-orm";
import { cockroachTable, bit } from "drizzle-orm/cockroach-core";

export const table = cockroachTable('table', {
	varbit1: varbit(),
	varbit2: varbit({ length: 15 }),
	varbit3: varbit({ length: 15 }).default('10011'),
	varbit4: varbit({ length: 15 }).default(sql`'10011'`)
});
```
```sql
CREATE TABLE "table" (
	"varbit1" varbit,
	"varbit2" varbit(15),
	"varbit3" varbit(15) DEFAULT '10011',
	"varbit4" varbit(15) DEFAULT '10011'
);
```

</Section>

## ---

### uuid
`uuid`

The UUID (Universally Unique Identifier) data type stores a 128-bit value that is unique across both space and time.

For more info please refer to the official CockroachDB **[docs.](https://www.cockroachlabs.com/docs/stable/uuid)**

```ts
import { uuid, cockroachTable } from "drizzle-orm/cockroach-core";

const table = cockroachTable('table', {
  uuid1: uuid(),
  uuid2: uuid().defaultRandom(),
  uuid3: uuid().default('a0ee-bc99-9c0b-4ef8-bb6d-6bb9-bd38-0a11')
});
```

```sql
CREATE TABLE "table" (
	"uuid1" uuid,
	"uuid2" uuid default gen_random_uuid(),
	"uuid3" uuid default 'a0ee-bc99-9c0b-4ef8-bb6d-6bb9-bd38-0a11'
);
```

## ---

### time
`time` `timetz` `time with timezone` `time without timezone`  

The `TIME` data type stores the time of day in UTC.
The `TIMETZ` data type stores a time of day with a time zone offset from UTC.

For more info please refer to the official CockroachDB **[docs.](https://www.cockroachlabs.com/docs/stable/time)**

<Section>
```typescript
import { time, cockroachTable } from "drizzle-orm/cockroach-core";

const table = cockroachTable('table', {
  time1: time(),
  time2: time({ withTimezone: true }),
  time3: time({ precision: 6 }),
  time4: time({ precision: 6, withTimezone: true })
});
```

```sql
CREATE TABLE "table" (
	"time1" time,
	"time2" time with timezone,
	"time3" time(6),
	"time4" time(6) with timezone
);
```
</Section>

### timestamp
`timestamp` `timestamptz` `timestamp with time zone` `timestamp without time zone`  

The TIMESTAMP and TIMESTAMPTZ data types store a date and time pair in UTC.

For more info please refer to the official CockroachDB **[docs.](https://www.cockroachlabs.com/docs/stable/timestamp)**
<Section>
```typescript
import { sql } from "drizzle-orm";
import { timestamp, cockroachTable } from "drizzle-orm/cockroach-core";

const table = cockroachTable('table', {
  timestamp1: timestamp(),
	timestamp2: timestamp({ precision: 6, withTimezone: true }),
	timestamp3: timestamp().defaultNow(),
	timestamp4: timestamp().default(sql`now()`),
});
```
```sql
CREATE TABLE "table" (
	"timestamp1" timestamp,
	"timestamp2" timestamp (6) with time zone,
	"timestamp3" timestamp default now(),
	"timestamp4" timestamp default now()
);
```
</Section>

You can specify either `date` or `string` infer modes:
```typescript
// will infer as date
timestamp: timestamp({ mode: "date" }),

// will infer as string
timestamp: timestamp({ mode: "string" }),
```

> The `string` mode does not perform any mappings for you. This mode was added to Drizzle ORM to provide developers
with the possibility to handle dates and date mappings themselves, depending on their needs.
Drizzle will pass raw dates as strings `to` and `from` the database, so the behavior should be as predictable as possible 
and aligned 100% with the database behavior

> The `date` mode is the regular way to work with dates. Drizzle will take care of all mappings between the database and the JS Date object

### date
`date`  

The DATE data type stores a year, month, and day.

For more info please refer to the official CockroachDB **[docs.](https://www.cockroachlabs.com/docs/stable/date)**
<Section>
```typescript
import { date, cockroachTable } from "drizzle-orm/cockroach-core";

const table = cockroachTable('table', {
	date: date(),
});
```

```sql
CREATE TABLE "table" (
	"date" date
);
```
</Section>
You can specify either `date` or `string` infer modes:
```typescript
// will infer as date
date: date({ mode: "date" }),

// will infer as string
date: date({ mode: "string" }),
```
### interval
`interval`  

Stores a value that represents a span of time.

For more info please refer to the official CockroachDB **[docs.](https://www.cockroachlabs.com/docs/stable/interval)** 

<Section>
```typescript
import { interval, cockroachTable } from "drizzle-orm/cockroach-core";

const table = cockroachTable('table', {
	interval1: interval(),
  interval2: interval({ fields: 'day' }),
  interval3: interval({ fields: 'month' , precision: 6 }),
});

```

```sql
CREATE TABLE "table" (
	"interval1" interval,
	"interval2" interval day,
	"interval3" interval(6) month
);
```
</Section>

## ---

### enum 
`enum` `enumerated types`  
Enumerated (enum) types are data types that comprise a static, ordered set of values. 
They are equivalent to the enum types supported in a number of programming languages. 
An example of an enum type might be the days of the week, or a set of status values for a piece of data.

For more info please refer to the official CockroachDB **[docs.](https://www.cockroachlabs.com/docs/stable/enum)**
<Section>
```typescript
import { cockroachEnum, cockroachTable } from "drizzle-orm/cockroach-core";

export const moodEnum = cockroachEnum('mood', ['sad', 'ok', 'happy']);

export const table = cockroachTable('table', {
  mood: moodEnum(),
});
```

```sql
CREATE TYPE mood AS ENUM ('sad', 'ok', 'happy');

CREATE TABLE "table" (
	"mood" mood
);
```
</Section>

## ---

### Customizing data type
Every column builder has a `.$type()` method, which allows you to customize the data type of the column. 

This is useful, for example, with unknown or branded types:
```ts
type UserId = number & { __brand: 'user_id' };
type Data = {
	foo: string;
	bar: number;
};

const users = cockroachTable('users', {
  id: int().$type<UserId>().primaryKey(),
  jsonField: json().$type<Data>(),
});
```

### Identity Columns

<Callout type="info">
To use this feature you would need to have `drizzle-orm@0.32.0` or higher and `drizzle-kit@0.23.0` or higher
</Callout>

PostgreSQL and CockroachDB supports identity columns as a way to automatically generate unique integer values for a column. These values are generated using sequences and can be defined using the GENERATED AS IDENTITY clause.

**Types of Identity Columns**
- `GENERATED ALWAYS AS IDENTITY`: The database always generates a value for the column. Manual insertion or updates to this column are not allowed unless the OVERRIDING SYSTEM VALUE clause is used.
- `GENERATED BY DEFAULT AS IDENTITY`: The database generates a value by default, but manual values can also be inserted or updated. If a manual value is provided, it will be used instead of the system-generated value.

**Usage example**
```ts
import { pgTable, integer, text } from 'drizzle-orm/pg-core' 

export const ingredients = pgTable("ingredients", {
  id: integer().primaryKey().generatedAlwaysAsIdentity({ startWith: 1000 }),
  name: text().notNull(),
  description: text(),
});
```

You can specify all properties available for sequences in the `.generatedAlwaysAsIdentity()` function. Additionally, you can specify custom names for these sequences

PostgreSQL docs [reference](https://www.postgresql.org/docs/current/sql-createtable.html#SQL-CREATETABLE-PARMS-GENERATED-IDENTITY).

### Default value
The `DEFAULT` clause specifies a default value to use for the column if no value
is explicitly provided by the user when doing an `INSERT`.
If there is no explicit `DEFAULT` clause attached to a column definition,
then the default value of the column is `NULL`.

An explicit `DEFAULT` clause may specify that the default value is `NULL`,
a string constant, a blob constant, a signed-number, or any constant expression enclosed in parentheses.

<Section>
```typescript
import { sql } from "drizzle-orm";
import { integer, pgTable, uuid } from "drizzle-orm/pg-core";

const table = pgTable('table', {
	integer1: integer().default(42),
	integer2: integer().default(sql`'42'::integer`),
	uuid1: uuid().defaultRandom(),
	uuid2: uuid().default(sql`gen_random_uuid()`),
});
```

```sql
CREATE TABLE IF NOT EXISTS "table" (
	"integer1" integer DEFAULT 42,
	"integer2" integer DEFAULT '42'::integer,
	"uuid1" uuid DEFAULT gen_random_uuid(),
	"uuid2" uuid DEFAULT gen_random_uuid()
);
```
</Section>

When using `$default()` or `$defaultFn()`, which are simply different aliases for the same function, 
you can generate defaults at runtime and use these values in all insert queries. 

These functions can assist you in utilizing various implementations such as `uuid`, `cuid`, `cuid2`, and many more.

<Callout type="info" emoji="ℹ️">
	Note: This value does not affect the `drizzle-kit` behavior, it is only used at runtime in `drizzle-orm`
</Callout>

```ts
import { text, pgTable } from "drizzle-orm/pg-core";
import { createId } from '@paralleldrive/cuid2';

const table = pgTable('table', {
	id: text().$defaultFn(() => createId()),
});
```

When using `$onUpdate()` or `$onUpdateFn()`, which are simply different aliases for the same function, 
you can generate defaults at runtime and use these values in all update queries. 

Adds a dynamic update value to the column. The function will be called when the row is updated, 
and the returned value will be used as the column value if none is provided.
If no default (or $defaultFn) value is provided, the function will be called
when the row is inserted as well, and the returned value will be used as the column value.

<Callout type="info" emoji="ℹ️">
	Note: This value does not affect the `drizzle-kit` behavior, it is only used at runtime in `drizzle-orm`
</Callout>

```ts
import { integer, timestamp, text, pgTable } from "drizzle-orm/pg-core";

const table = pgTable('table', {
	updateCounter: integer().default(sql`1`).$onUpdateFn((): SQL => sql`${table.update_counter} + 1`),
	updatedAt: timestamp({ mode: 'date', precision: 3 }).$onUpdate(() => new Date()),
    	alwaysNull: text().$type<string | null>().$onUpdate(() => null),
});
```


### Not null
`NOT NULL` constraint dictates that the associated column may not contain a `NULL` value.

<Section>
```typescript
import { integer, pgTable } from "drizzle-orm/pg-core";

const table = pgTable('table', {
	integer: integer().notNull(),
});
```

```sql
CREATE TABLE IF NOT EXISTS "table" (
	"integer" integer NOT NULL
);
```
</Section>


### Primary key
A primary key constraint indicates that a column, or group of columns, can be used as a unique identifier for rows in the table. 
This requires that the values be both unique and not null.
<Section>
```typescript
import { serial, pgTable } from "drizzle-orm/pg-core";

const table = pgTable('table', {
	id: serial().primaryKey(),
});
```

```sql
CREATE TABLE IF NOT EXISTS "table" (
	"id" serial PRIMARY KEY NOT NULL
);
```
</Section>


Source: https://orm.drizzle.team/docs/column-types/mssql


import Section from '@mdx/Section.astro';
import Callout from '@mdx/Callout.astro';
import Npm from '@mdx/Npm.astro';

<Callout type='error'>
This page explains concepts available on drizzle versions `1.0.0-beta.2` and higher.
</Callout>

<Npm>
drizzle-orm@rc
drizzle-kit@rc -D
</Npm>

<br/>

We have native support for all of them, yet if that's not enough for you, feel free to create **[custom types](/docs/custom-types)**.

<Callout title='important' type='warning'>
All examples in this part of the documentation do not use database column name aliases, and column names are generated from TypeScript keys. 

You can use database aliases in column names if you want, and you can also use the `casing` parameter to define a mapping strategy for Drizzle. 

You can read more about it [here](/docs/sql-schema-declaration#shape-your-data-schema)
</Callout>

### int
Signed 4-byte integer     

<Section>
```typescript
import { int, mssqlTable } from "drizzle-orm/mssql-core";

export const table = mssqlTable('table', {
	int: int()
});

```

```sql
CREATE TABLE [table] (
	[int] int
);
```
</Section>

<Section>
```typescript
import { sql } from "drizzle-orm";
import { int, mssqlTable } from "drizzle-orm/mssql-core";

export const table = pgTable('table', {
	int1: int().default(10),
});

```

```sql
CREATE TABLE [table] (
	[int1] int DEFAULT 10
);
```
</Section>

### smallint
`smallint`

Small-range signed 2-byte integer   

<Section>
```typescript
import { smallint, mssqlTable } from "drizzle-orm/mssql-core";

export const table = mssqlTable('table', {
	smallint: smallint()
});
```

```sql
CREATE TABLE [table] (
	[smallint] smallint
);
```
</Section>

<Section>
```typescript
import { sql } from "drizzle-orm";
import { smallint, mssqlTable } from "drizzle-orm/mssql-core";

export const table = mssqlTable('table', {
	smallint1: smallint().default(10),
});
```

```sql
CREATE TABLE [table] (
	[smallint1] smallint DEFAULT 10
);
```
</Section>

### tinyint
`tinyint`

Small-range signed 1-byte integer   

<Section>
```typescript
import { tinyint, mssqlTable } from "drizzle-orm/mssql-core";

export const table = mssqlTable('table', {
	tinyint: tinyint()
});
```

```sql
CREATE TABLE [table] (
	[tinyint] tinyint
);
```
</Section>

<Section>
```typescript
import { sql } from "drizzle-orm";
import { tinyint, mssqlTable } from "drizzle-orm/mssql-core";

export const table = mssqlTable('table', {
	tinyint1: tinyint().default(10),
});
```

```sql
CREATE TABLE [table] (
	[tinyint1] tinyint DEFAULT 10
);
```
</Section>

### bigint
`bigint`

Signed 8-byte integer  

If you're expecting values above 2^31 but below 2^53, you can utilise `mode: 'number'` and deal with javascript number as opposed to bigint.
<Section>
```typescript
import { bigint, mssqlTable } from "drizzle-orm/mssql-core";

export const table = mssqlTable('table', {
	bigint: bigint({ mode: 'number' })
});

// will be inferred as `number`
bigint: bigint({ mode: 'number' })

// will be inferred as `bigint`
bigint: bigint({ mode: 'bigint' })

// will be inferred as `string`
bigint: bigint({ mode: 'string' })
```

```sql
CREATE TABLE [table] (
	[bigint] bigint
);
```
</Section>

<Section>
```typescript
import { sql } from "drizzle-orm";
import { bigint, mssqlTable } from "drizzle-orm/mssql-core";

export const table = mssqlTable('table', {
	bigint1: bigint({ mode: 'number' }).default(10)
});
```

```sql
CREATE TABLE [table] (
	[bigint1] bigint DEFAULT 10
);
```
</Section>

## ---

### bit

An integer data type that can take a value of `1`, `0`, or `NULL`

Drizzle will accept `true` or `false` as values instead of `1` and `0`

<Section>
```typescript
import { bit, mssqlTable } from "drizzle-orm/mssql-core";

export const table = mssqlTable('table', {
	bit: bit()
});

```

```sql
CREATE TABLE [table] (
	[bit] bit
);
```
</Section>

## ---

### text
`text`  
Variable-length non-Unicode data in the code page of the server and with a maximum string length 
of 2^31 - 1 (2,147,483,647)

For more info please refer to the official MSSQL **[docs.](https://learn.microsoft.com/en-us/sql/t-sql/data-types/ntext-text-and-image-transact-sql?view=sql-server-ver17#text)**
  
You can define `{ enum: ["value1", "value2"] }` config to infer `insert` and `select` types, it **won't** check runtime values.
<Section>
```typescript
import { text, mssqlTable } from "drizzle-orm/mssql-core";

export const table = mssqlTable('table', {
  text: text()
});

// will be inferred as text: "value1" | "value2" | null
text: text({ enum: ["value1", "value2"] })
```

```sql
CREATE TABLE [table] (
	[text] text
);
```
</Section>

### ntext
`text`  
Variable-length Unicode data with a maximum string length of 2^30 - 1 (1,073,741,823).

For more info please refer to the official MSSQL **[docs.](https://learn.microsoft.com/en-us/sql/t-sql/data-types/ntext-text-and-image-transact-sql?view=sql-server-ver17#text)**
  
You can define `{ enum: ["value1", "value2"] }` config to infer `insert` and `select` types, it **won't** check runtime values.
<Section>
```typescript
import { text, mssqlTable } from "drizzle-orm/mssql-core";

export const table = mssqlTable('table', {
  ntext: ntext()
});

// will be inferred as text: "value1" | "value2" | null
ntext: ntext({ enum: ["value1", "value2"] })
```

```sql
CREATE TABLE [table] (
	[ntext] ntext
);
```
</Section>

### varchar
`varchar(n|max)`  
Variable-size string data. Use n to define the string size in bytes and can be a value from 1 through 8,000

For more info please refer to the official MSSQL **[docs.](https://learn.microsoft.com/en-us/sql/t-sql/data-types/char-and-varchar-transact-sql?view=sql-server-ver17#varchar---n--max--)**

You can define `{ enum: ["value1", "value2"] }` config to infer `insert` and `select` types, it **won't** check runtime values.

The `length` parameter is optional according to MSSQL docs.
<Section>
```typescript
import { varchar, mssqlTable } from "drizzle-orm/mssql-core";

export const table = mssqlTable('table', {
  varchar1: varchar(),
  varchar2: varchar({ length: 256 }),
  varchar3: varchar({ length: 'max' })
});

// will be inferred as text: "value1" | "value2" | null
varchar: varchar({ enum: ["value1", "value2"] }),
```

```sql
CREATE TABLE [table] (
	[varchar1] varchar,
	[varchar2] varchar(256),
	[varchar3] varchar(max)
);
```
</Section>

### nvarchar
`nvarchar(n|max)`  
Variable-size string data. The value of n defines the string size in byte-pairs

For more info please refer to the official MSSQL **[docs.](https://learn.microsoft.com/en-us/sql/t-sql/data-types/nchar-and-nvarchar-transact-sql?view=sql-server-ver17#nvarchar---n--max--)**

You can define `{ enum: ["value1", "value2"] }` config to infer `insert` and `select` types, it **won't** check runtime values.

The `length` parameter is optional according to MSSQL docs.
<Section>
```typescript
import { nvarchar, mssqlTable } from "drizzle-orm/mssql-core";

export const table = mssqlTable('table', {
  nvarchar1: nvarchar(),
  nvarchar2: nvarchar({ length: 256 }),
});

// will be inferred as text: "value1" | "value2" | null
nvarchar: nvarchar({ enum: ["value1", "value2"] }),

// will be inferred as `json`
nvarchar: nvarchar({ mode: 'json' })
```

```sql
CREATE TABLE [table] (
	[nvarchar1] nvarchar,
	[nvarchar2] nvarchar(256)
);
```
</Section>

### char
`char(n)`  

Fixed-size string data. n defines the string size in bytes and must be a value from 1 through 8,000

For more info please refer to the official MSSQL **[docs.](https://learn.microsoft.com/en-us/sql/t-sql/data-types/char-and-varchar-transact-sql?view=sql-server-ver17#char---n--)**

You can define `{ enum: ["value1", "value2"] }` config to infer `insert` and `select` types, it **won't** check runtime values.

The `length` parameter is optional according to MSSQL docs.
<Section>
```typescript
import { char, mssqlTable } from "drizzle-orm/mssql-core";

export const table = mssqlTable('table', {
  char1: char(),
  char2: char({ length: 256 }),
});

// will be inferred as text: "value1" | "value2" | null
char: char({ enum: ["value1", "value2"] }),
```

```sql
CREATE TABLE [table] (
	[char1] char,
	[char2] char(256)
);
```
</Section>

### nchar
`nchar(n)`  

Fixed-size string data. n defines the string size in byte-pairs, and must be a value from 1 through 4,000

For more info please refer to the official MSSQL **[docs.](https://learn.microsoft.com/en-us/sql/t-sql/data-types/nchar-and-nvarchar-transact-sql?view=sql-server-ver17#nchar---n--)**

You can define `{ enum: ["value1", "value2"] }` config to infer `insert` and `select` types, it **won't** check runtime values.

The `length` parameter is optional according to MSSQL docs.
<Section>
```typescript
import { nchar, mssqlTable } from "drizzle-orm/mssql-core";

export const table = mssqlTable('table', {
  nchar1: nchar(),
  nchar2: nchar({ length: 256 }),
});

// will be inferred as text: "value1" | "value2" | null
nchar: nchar({ enum: ["value1", "value2"] }),
```

```sql
CREATE TABLE [table] (
	[nchar1] nchar,
	[nchar2] nchar(256)
);
```
</Section>

## ---

### binary

Fixed-length binary data with a length of n bytes, where n is a value from 1 through 8,000. The storage size is n bytes.

<Section>
```typescript
import { binary, mssqlTable } from "drizzle-orm/mssql-core";

const table = mssqlTable('table', {
	binary: binary(),
	binary1: binary({ length: 256 })
});
```

```sql
CREATE TABLE [table] (
	[binary] binary,
	[binary1] binary(256)
);
```
</Section>

### varbinary

Variable-length binary data. n can be a value from 1 through 8,000. max indicates that the maximum storage size is 2^31-1 bytes

<Section>
```typescript
import { varbinary, mssqlTable } from "drizzle-orm/mssql-core";

const table = mssqlTable('table', {
	varbinary: varbinary(),
	varbinary1: varbinary({ length: 256 }),
	varbinary2: varbinary({ length: 'max' })
});
```

```sql
CREATE TABLE [table] (
	[varbinary] varbinary,
	[varbinary1] varbinary(256),
	[varbinary2] varbinary(max)
);
```
</Section>

## ---

### numeric
`numeric`

Fixed precision and scale numbers. When maximum precision is used, valid values are from -10^38 + 1 through 10^38 - 1

For more info please refer to the official MSSQL **[docs.](https://learn.microsoft.com/en-us/sql/t-sql/data-types/decimal-and-numeric-transact-sql?view=sql-server-ver17#decimal---p---s----and-numeric---p---s---)**

<Section>
```typescript
import { numeric, mssqlTable } from "drizzle-orm/mssql-core";

export const table = mssqlTable('table', {
  numeric1: numeric(),
  numeric2: numeric({ precision: 100 }),
  numeric3: numeric({ precision: 100, scale: 20 })
//   numericNum: numeric({ mode: 'number' }),
//   numericBig: numeric({ mode: 'bigint' }),
});
```

```sql
CREATE TABLE [table] (
	[numeric1] numeric,
	[numeric2] numeric(100),
	[numeric3] numeric(100, 20)
);
```
</Section>

### decimal
An alias of **[numeric.](#numeric)**

### real

The ISO synonym for real is float(24).

For more info please refer to the official MSSQL **[docs.](https://learn.microsoft.com/en-us/sql/t-sql/data-types/float-and-real-transact-sql?view=sql-server-ver17)**  

<Section>
```typescript
import { sql } from "drizzle-orm";
import { real, mssqlTable } from "drizzle-orm/mssql-core";  

const table = mssqlTable('table', {
	real1: real(),
	real2: real().default(10.10)
});
```

```sql
CREATE TABLE [table] (
	[real1] real,
	[real2] real default 10.10
);
```
</Section>

### float

float [ (n) ] Where n is the number of bits that are used to store the mantissa of the float number in scientific notation and, therefore, dictates the precision and storage size. If n is specified, it must be a value between 1 and 53. The default value of n is 53.

For more info please refer to the official MSSQL **[docs.](https://learn.microsoft.com/en-us/sql/t-sql/data-types/float-and-real-transact-sql?view=sql-server-ver17#syntax)**  

<Section>
```typescript
import { sql } from "drizzle-orm";
import { float, mssqlTable } from "drizzle-orm/mssql-core";

const table = mssqlTable('table', {
	float1: float(),
	float1: float({ precision: 16 })
});
```

```sql
CREATE TABLE [table] (
	[float1] float,
	[float2] float(16)
);
```
</Section>

## ---

### time
`time`

Defines a time of a day. The time is without time zone awareness and is based on a 24-hour clock.

For more info please refer to the official MSSQL **[docs.](https://learn.microsoft.com/en-us/sql/t-sql/data-types/time-transact-sql?view=sql-server-ver17#time-description)**

<Section>
```typescript
import { time, mssqlTable } from "drizzle-orm/mssql-core";

const table = mssqlTable('table', {
  time1: time(),
  time2: time({ mode: 'string' }),
  time3: time({ precision: 6 }),
  time4: time({ precision: 6, mode: 'date' })
});
```

```sql
CREATE TABLE [table] (
	[time1] time,
	[time2] time,
	[time3] time(6),
	[time4] time(6)
);
```
</Section>

### date
`date`  

Calendar date (year, month, day)

For more info please refer to the official MSSQL **[docs.](https://learn.microsoft.com/en-us/sql/t-sql/data-types/date-transact-sql?view=sql-server-ver17#date-description)**
<Section>
```typescript
import { date, mssqlTable } from "drizzle-orm/mssql-core";

const table = mssqlTable('table', {
	date: date(),
});
```

```sql
CREATE TABLE [table] (
	[date] date
);
```
</Section>
You can specify either `date` or `string` infer modes:
```typescript
// will infer as date
date: date({ mode: "date" }),

// will infer as string
date: date({ mode: "string" }),
```

### datetime
`datetime`  

Defines a date that is combined with a time of day with fractional seconds that is based on a 24-hour clock.

<Callout title='MSSQL docs'>
Avoid using datetime for new work. Instead, use the time, date, datetime2, and datetimeoffset data types. These types align with the SQL Standard, and are more portable. time, datetime2 and datetimeoffset provide more seconds precision. datetimeoffset provides time zone support for globally deployed applications.
</Callout>

For more info please refer to the official MSSQL **[docs.](https://learn.microsoft.com/en-us/sql/t-sql/data-types/datetime-transact-sql?view=sql-server-ver17#description)**
<Section>
```typescript
import { datetime, mssqlTable } from "drizzle-orm/mssql-core";

const table = mssqlTable('table', {
	datetime: datetime(),
});
```

```sql
CREATE TABLE [table] (
	[datetime] datetime
);
```
</Section>
You can specify either `date` or `string` infer modes:
```typescript
// will infer as date
datetime: datetime({ mode: "date" }),

// will infer as string
datetime: datetime({ mode: "string" }),
```

### datetime2
`datetime2`  

Defines a date that is combined with a time of day that is based on 24-hour clock. datetime2 can be considered as an extension of the existing datetime type that has a larger date range, a larger default fractional precision, and optional user-specified precision.

For more info please refer to the official MSSQL **[docs.](https://learn.microsoft.com/en-us/sql/t-sql/data-types/datetime2-transact-sql?view=sql-server-ver17#datetime2-description)**
<Section>
```typescript
import { datetime2, mssqlTable } from "drizzle-orm/mssql-core";

const table = mssqlTable('table', {
	datetime2: datetime2(),
});
```

```sql
CREATE TABLE [table] (
	[datetime2] datetime2
);
```
</Section>
You can specify either `date` or `string` infer modes:
```typescript
// will infer as date
datetime2: datetime2({ mode: "date" }),

// will infer as string
datetime2: datetime2({ mode: "string" }),
```

### datetimeoffset
`datetimeoffset`  

Defines a date that is combined with a time of a day based on a 24-hour clock like datetime2, and adds time zone awareness based on Coordinated Universal Time (UTC).

For more info please refer to the official MSSQL **[docs.](https://learn.microsoft.com/en-us/sql/t-sql/data-types/datetimeoffset-transact-sql?view=sql-server-ver17#datetimeoffset-description)**
<Section>
```typescript
import { datetimeoffset, mssqlTable } from "drizzle-orm/mssql-core";

const table = mssqlTable('table', {
	datetimeoffset: datetimeoffset(),
});
```

```sql
CREATE TABLE [table] (
	[datetimeoffset] datetimeoffset
);
```
</Section>
You can specify either `date` or `string` infer modes:
```typescript
// will infer as date
datetimeoffset: datetimeoffset({ mode: "date" }),

// will infer as string
datetimeoffset: datetimeoffset({ mode: "string" }),
```

## ---

### Customizing data type
Every column builder has a `.$type()` method, which allows you to customize the data type of the column. 

This is useful, for example, with unknown or branded types:
```ts
type UserId = number & { __brand: 'user_id' };
type Data = {
	foo: string;
	bar: number;
};

const users = mssqlTable('users', {
  id: int().$type<UserId>().primaryKey(),
  jsonField: json().$type<Data>(),
});
```

### Default value
The `DEFAULT` clause specifies a default value to use for the column if no value
is explicitly provided by the user when doing an `INSERT`.
If there is no explicit `DEFAULT` clause attached to a column definition,
then the default value of the column is `NULL`.

An explicit `DEFAULT` clause may specify that the default value is `NULL`,
a string constant, a blob constant, a signed-number, or any constant expression enclosed in parentheses.

<Section>
```typescript
import { sql } from "drizzle-orm";
import { int, mssqlTable, text } from "drizzle-orm/mssql-core";

const table = mssqlTable('table', {
	integer: integer().default(42),
	text: text().default('text'),
});
```

```sql
CREATE TABLE [table] (
	[integer1] integer DEFAULT 42,
	[text] text DEFAULT 'text',
);
```
</Section>

When using `$default()` or `$defaultFn()`, which are simply different aliases for the same function, 
you can generate defaults at runtime and use these values in all insert queries. 

<Callout type="info" emoji="ℹ️">
	Note: This value does not affect the `drizzle-kit` behavior, it is only used at runtime in `drizzle-orm`
</Callout>

```ts
import { text, mssqlTable } from "drizzle-orm/mssql-core";
import { createId } from '@paralleldrive/cuid2';

const table = mssqlTable('table', {
	id: text().$defaultFn(() => createId()),
});
```

When using `$onUpdate()` or `$onUpdateFn()`, which are simply different aliases for the same function, 
you can generate defaults at runtime and use these values in all update queries. 

Adds a dynamic update value to the column. The function will be called when the row is updated, 
and the returned value will be used as the column value if none is provided.
If no default (or $defaultFn) value is provided, the function will be called
when the row is inserted as well, and the returned value will be used as the column value.

<Callout type="info" emoji="ℹ️">
	Note: This value does not affect the `drizzle-kit` behavior, it is only used at runtime in `drizzle-orm`
</Callout>

```ts
import { int, datetime2, text, mssqlTable } from "drizzle-orm/mssql-core";

const table = mssqlTable('table', {
	updateCounter: int().default(sql`1`).$onUpdateFn((): SQL => sql`${table.updateCounter} + 1`),
	updatedAt: datetime2({ mode: 'date', precision: 3 }).$onUpdate(() => new Date()),
	alwaysNull: text().$type<string | null>().$onUpdate(() => null),
});
```


### Not null
`NOT NULL` constraint dictates that the associated column may not contain a `NULL` value.

<Section>
```typescript
import { int, mssqlTable } from "drizzle-orm/mssql-core";

const table = mssqlTable('table', {
	int: int().notNull(),
});
```

```sql
CREATE TABLE [table] (
	[int] int NOT NULL
);
```
</Section>


### Primary key
A primary key constraint indicates that a column, or group of columns, can be used as a unique identifier for rows in the table. 
This requires that the values be both unique and not null.
<Section>
```typescript
import { int, mssqlTable } from "drizzle-orm/mssql-core";

const table = pgTable('table', {
	id: int().primaryKey(),
});
```

```sql
CREATE TABLE [table] (
	[id] int PRIMARY KEY
);
```
</Section>


Source: https://orm.drizzle.team/docs/data-querying

import Callout from '@mdx/Callout.astro';
import CodeTabs from "@mdx/CodeTabs.astro";
import Section from '@mdx/Section.astro';
import Flex from "@mdx/Flex.astro"
import LinksList from "@mdx/LinksList.astro"
import Prerequisites from "@mdx/Prerequisites.astro";

# Drizzle Queries + CRUD

<Prerequisites>
  - How to define your schema - [Schema Fundamentals](/docs/sql-schema-declaration)
  - How to connect to the database - [Connection Fundamentals](/docs/connect-overview)
</Prerequisites>

Drizzle gives you a few ways for querying your database and it's up to you to decide which one you'll need in your next project.
It can be either SQL-like syntax or Relational Syntax. Let's check them:

## Why SQL-like?
\
**If you know SQL, you know Drizzle.**

Other ORMs and data frameworks tend to deviate from or abstract away SQL, leading to a double learning curve: you need to learn both SQL and the framework's API.

Drizzle is the opposite.
We embrace SQL and built Drizzle to be SQL-like at its core, so you have little to no learning curve and full access to the power of SQL.

<Section>
```typescript copy
// Access your data
await db
  .select()
	.from(posts)
	.leftJoin(comments, eq(posts.id, comments.post_id))
	.where(eq(posts.id, 10))
```
```sql
SELECT * 
FROM posts
LEFT JOIN comments ON posts.id = comments.post_id
WHERE posts.id = 10
```
</Section>

With SQL-like syntax, you can replicate much of what you can do with pure SQL and know 
exactly what Drizzle will do and what query will be generated. You can perform a wide range of queries, 
including select, insert, update, delete, as well as using aliases, WITH clauses, subqueries, prepared statements, 
and more. Let's look at more examples

<CodeTabs items={['insert', 'update', 'delete']}>
<Section>
```ts
await db.insert(users).values({ email: 'user@gmail.com' })
```
```sql
INSERT INTO users (email) VALUES ('user@gmail.com')
```
</Section>
<Section>
```ts
await db.update(users)
        .set({ email: 'user@gmail.com' })
        .where(eq(users.id, 1))
```
```sql
UPDATE users 
SET email = 'user@gmail.com'
WHERE users.id = 1
```
</Section>
<Section>
```ts
await db.delete(users).where(eq(users.id, 1))
```
```sql
DELETE FROM users WHERE users.id = 1
```
</Section>
</CodeTabs>

## Why not SQL-like?

We're always striving for a perfectly balanced solution. While SQL-like queries cover 100% of your needs, 
there are certain common scenarios where data can be queried more efficiently.

We've built the Queries API so you can fetch relational, nested data from the database in the most convenient 
and performant way, without worrying about joins or data mapping.

**Drizzle always outputs exactly one SQL query**. Feel free to use it with serverless databases,
and never worry about performance or roundtrip costs!

<Section>
```ts
const result = await db.query.users.findMany({
	with: {
		posts: true
	},
});
```
{/* ```sql
SELECT * FROM users ...
``` */}
</Section>

## Advanced
With Drizzle, queries can be composed and partitioned in any way you want. You can compose filters 
independently from the main query, separate subqueries or conditional statements, and much more. 
Let's check a few advanced examples:

#### Compose a WHERE statement and then use it in a query
```ts
async function getProductsBy({
  name,
  category,
  maxPrice,
}: {
  name?: string;
  category?: string;
  maxPrice?: number;
}) {
  const filters: SQL[] = [];

  if (name) filters.push(ilike(products.name, name));
  if (category) filters.push(eq(products.category, category));
  if (maxPrice) filters.push(lte(products.price, maxPrice));

  return db
    .select()
    .from(products)
    .where(and(...filters));
}
```

#### Separate subqueries into different variables, and then use them in the main query
```ts
const subquery = db
	.select()
	.from(internalStaff)
	.leftJoin(customUser, eq(internalStaff.userId, customUser.id))
	.as('internal_staff');

const mainQuery = await db
	.select()
	.from(ticket)
	.leftJoin(subquery, eq(subquery.internal_staff.userId, ticket.staffId));
```

#### What's next?
<br/>
<Flex>
  <LinksList 
    title='Access your data'
    links={[
        ["Query", "/docs/rqb"], 
        ["Select", "/docs/select"],
        ["Insert", "/docs/insert"],
        ["Update", "/docs/update"],
        ["Delete", "/docs/delete"],
        ["Filters", "/docs/operators"],
        ["Joins", "/docs/joins"],
        ["sql`` operator", "/docs/sql"],
      ]}
  />
  <LinksList 
    title='Zero to Hero'
    links={[
        ["Migrations", "/docs/migrations"], 
      ]}
  />
</Flex>


Source: https://orm.drizzle.team/docs/drizzle-config-file

import CodeTab from "@mdx/CodeTab.astro";
import CodeTabs from "@mdx/CodeTabs.astro";
import Section from "@mdx/Section.astro";
import Tab from "@mdx/Tab.astro";
import Tabs from "@mdx/Tabs.astro";
import Callout from "@mdx/Callout.astro";
import SchemaFilePaths from "@mdx/SchemaFilePaths.mdx"
import Prerequisites from "@mdx/Prerequisites.astro"
import Dialects from "@mdx/Dialects.mdx"
import Drivers from "@mdx/Drivers.mdx"
import DriversExamples from "@mdx/DriversExamples.mdx"
import Npx from "@mdx/Npx.astro"

# Drizzle Kit configuration file
<Prerequisites>
- Get started with Drizzle and `drizzle-kit` - [read here](/docs/get-started)
- Drizzle schema fundamentals - [read here](/docs/sql-schema-declaration)
- Database connection basics - [read here](/docs/connect-overview)
- Drizzle migrations fundamentals - [read here](/docs/migrations)
- Drizzle Kit [overview](/docs/kit-overview) and [config file](/docs/drizzle-config-file)
</Prerequisites>

Drizzle Kit lets you declare configuration options in `TypeScript` or `JavaScript` configuration files.

<Section>
```plaintext {5}
📦 <project root>
 ├ ...
 ├ 📂 drizzle
 ├ 📂 src
 ├ 📜 drizzle.config.ts
 └ 📜 package.json
```
<CodeTabs items={["drizzle.config.ts", "drizzle.config.js"]}>
<CodeTab>
```ts
import { defineConfig } from "drizzle-kit";

export default defineConfig({
  dialect: "postgresql",
  schema: "./src/schema.ts",
  out: "./drizzle",
});
```
</CodeTab>
<CodeTab>
```js
import { defineConfig } from "drizzle-kit";

export default defineConfig({
  dialect: "postgresql",
  schema: "./src/schema.ts",
  out: "./drizzle",
});
```
</CodeTab>
</CodeTabs>
</Section>

Example of an extended config file
```ts collapsable
import { defineConfig } from "drizzle-kit";

export default defineConfig({
  out: "./drizzle",
  dialect: "postgresql",
  schema: "./src/schema.ts",

  driver: "pglite",
  dbCredentials: {
    url: "./database/",
  },

  extensionsFilters: ["postgis"],
  schemaFilter: "public",
  tablesFilter: "*",

  introspect: {
    casing: "camel",
  },

  migrations: {
    table: "__drizzle_migrations__",
    schema: "public",
  },

  entities: {
    roles: {
      provider: '',
      exclude: [],
      include: []
    }
  },

  breakpoints: true,
  verbose: true,
});
```

### Multiple configuration files
You can have multiple config files in the project, it's very useful when you have multiple database stages or multiple databases or different databases on the same project:
<Npx>
  drizzle-kit generate --config=drizzle-dev.config.ts
  drizzle-kit generate --config=drizzle-prod.config.ts
</Npx>
```plaintext {5-6}
📦 <project root>
 ├ 📂 drizzle
 ├ 📂 src
 ├ 📜 .env
 ├ 📜 drizzle-dev.config.ts
 ├ 📜 drizzle-prod.config.ts
 ├ 📜 package.json
 └ 📜 tsconfig.json
```

### Migrations folder
`out` param lets you define folder for your migrations, it's optional and `drizzle` by default.  
It's very useful since you can have many separate schemas for different databases in the same project 
and have different migration folders for them.  
  
Migration folder contains folders with `.sql` migration files which is used by `drizzle-kit`

<Section>
```plaintext {3}
📦 <project root>
 ├ ...
 ├ 📂 drizzle
 │ ├ 📂 20242409125510_premium_mister_fear
 │ ├ 📜 user.ts 
 │ ├ 📜 post.ts 
 │ └ 📜 comment.ts 
 ├ 📂 src
 ├ 📜 drizzle.config.ts
 └ 📜 package.json
```
```ts {6}
import { defineConfig } from "drizzle-kit";

export default defineConfig({
  dialect: "postgresql",
  schema: "./src/schema/*",
  out: "./drizzle",
});
```
</Section>

## ---

### `dialect`
<rem025/>

Dialect of the database you're using 
|               |                                                 |
| :------------ | :-----------------------------------            |
| type        | <Dialects/>                                     |
| default        | --                                     |
| commands    | `generate`, `push`, `pull`, `studio`,  `migrate`, `up`, `export`, |

<rem025/>
```ts {4}
import { defineConfig } from "drizzle-kit";

export default defineConfig({
  dialect: "postgresql", 
});
```


### `schema`
<rem025/>

[`glob`](https://www.digitalocean.com/community/tools/glob?comments=true&glob=/**/*.js&matches=false&tests=//%20This%20will%20match%20as%20it%20ends%20with%20'.js'&tests=/hello/world.js&tests=//%20This%20won't%20match!&tests=/test/some/globs)
 based path to drizzle schema file(s) or folder(s) contaning schema files.
|               |                      |
| :------------ | :-----------------   |
| type          | `string` `string[]` |
| default        | --                    |
| commands      | `generate`, `push`, `export`, `studio`    |

<rem025/>
<SchemaFilePaths />


### `out`
<rem025/>

Defines output folder of your SQL migration files, json snapshots of your schema and `schema.ts` from `drizzle-kit pull` command.
|               |                      |
| :------------ | :-----------------   |
| type          | `string` `string[]` |
| default        | `drizzle`                    |
| commands      | `generate`, `pull`, `migrate`, `check`, `up` |

<rem025/>
```ts {4}
import { defineConfig } from "drizzle-kit";

export default defineConfig({
  out: "./drizzle", 
});
```

### `driver`
<rem025/>

Drizzle Kit automatically picks available database driver from your current project based on the provided `dialect`, 
yet some vendor specific databases require a different subset of connection params.

`driver` option let's you explicitely pick those exceptions drivers.

|               |                      |
| :------------ | :-----------------   |
| type          | <Drivers/> |
| default        | --                    |
| commands      | `push`, `migrate`, `pull`, `studio`  |

<rem025/>

<DriversExamples/>

## ---

### `dbCredentials`
<rem025/>

Database connection credentials in a form of `url`, 
`user:password@host:port/db` params or exceptions drivers(<Drivers/>) specific connection options.

|               |                      |
| :------------ | :-----------------   |
| type          | <Dialects/> |
| default       | --                    |
| commands      | `push`, `pull`, `migrate`, `studio` |

<rem025/>

<CodeTabs items={["PostgreSQL", "MySQL", "SQLite", "MSSQL", "Cockroach", "Turso", "Cloudflare D1", "AWS Data API", "PGLite"]}>
<Section>
```ts
import { defineConfig } from 'drizzle-kit'

export default defineConfig({
  dialect: "postgresql",
  dbCredentials: {
    url: "postgres://user:password@host:port/db",
  }
});
```
```ts
import { defineConfig } from 'drizzle-kit'

// via connection params
export default defineConfig({
  dialect: "postgresql",
  dbCredentials: {
    host: "host",
    port: 5432,
    user: "user",
    password: "password",
    database: "dbname",
    ssl: true, // can be boolean | "require" | "allow" | "prefer" | "verify-full" | options from node:tls
  }
});
```
</Section>
<Section>
```ts
import { defineConfig } from 'drizzle-kit'

export default defineConfig({
  dialect: "mysql",
  dbCredentials: {
    url: "mysql://user:password@host:port/db",
  }
});
```
```ts
import { defineConfig } from 'drizzle-kit'

// via connection params
export default defineConfig({
  dialect: "mysql",
  dbCredentials: {
    host: "host",
    port: 5432,
    user: "user",
    password: "password",
    database: "dbname",
    ssl: "...", // can be: string | SslOptions (ssl options from mysql2 package)
  }
});
```
</Section>
```ts
import { defineConfig } from 'drizzle-kit'

export default defineConfig({
  dialect: "sqlite",
  dbCredentials: {
    url: ":memory:", // inmemory database
    // or
    url: "sqlite.db", 
    // or
    url: "file:sqlite.db" // file: prefix is required by libsql
  }
});
```
<Section>
```ts
import { defineConfig } from 'drizzle-kit'

export default defineConfig({
  dialect: "mssql",
  dbCredentials: {
    url: "mssql://username:password@host:port/database",
  }
});
```
```ts
import { defineConfig } from 'drizzle-kit'

// via connection params
export default defineConfig({
  dialect: "mssql",
  dbCredentials: {
    database: "database",
    password: "password",
    port: 1433,
    server: "server",
    user: "user",
    options: {
      encrypt: true, // boolean
      trustServerCertificate: false, // boolean
    },
  },
});
```
</Section>
```ts
import { defineConfig } from 'drizzle-kit'

export default defineConfig({
  dialect: "turso",
  dbCredentials: {
    url: "libsql://acme.turso.io" // remote Turso database url
    authToken: "...",

    // or if you need local db

    url: ":memory:", // inmemory database
    // or
    url: "file:sqlite.db", // file: prefix is required by libsql
  }
});
```
```ts
import { defineConfig } from 'drizzle-kit'

export default defineConfig({
  dialect: "sqlite",
  driver: "d1-http",
  dbCredentials: {
    accountId: "",
    databaseId: "",
    token: "",
  }
});
```
```ts
import { defineConfig } from 'drizzle-kit'

export default defineConfig({
  dialect: "postgresql",
  driver: "aws-data-api",
  dbCredentials: {
    database: "database",
    resourceArn: "resourceArn",
    secretArn: "secretArn",
  },
});
```
```ts
import { defineConfig } from 'drizzle-kit'

export default defineConfig({
  dialect: "postgresql",
  driver: "pglite",
  dbCredentials: {
    url: "./database/", // database folder path
  }
});
```
</CodeTabs>

### `migrations`
<rem025/>

When running `drizzle-kit migrate` - drizzle will records about 
successfully applied migrations in your database in log table named `__drizzle_migrations` in `public` schema (schema is used in PostgreSQL only).

`migrations` config options lets you change both migrations log `table` name and `schema`.

|               |                      |
| :------------ | :-----------------   |
| type          | `{ table: string, schema: string }` |
| default       | `{ table: "__drizzle_migrations", schema: "drizzle" }`                    |
| commands      | `migrate`, `push`, `pull`   |

<rem025/>

```ts
export default defineConfig({
  dialect: "postgresql",
  schema: "./src/schema.ts",
  migrations: {
    table: 'my-migrations-table', // `__drizzle_migrations` by default
    schema: 'public', // used in PostgreSQL only, `drizzle` by default
  },
});
```

### `introspect`
<rem025/>

Configuration for `drizzle-kit pull` command.

`casing` is responsible for in-code column keys casing

|               |                      |
| :------------ | :-----------------   |
| type          | `{ casing: "preserve" \| "camel" }` |
| default       | `{ casing: "camel" }`                    |
| commands      | `pull`   |

<rem025/>

<CodeTabs items={["camel", "preserve"]}>
<Section>
```ts
import * as p from "drizzle-orm/pg-core"

export const users = p.pgTable("users", {
  id: p.serial(),
  firstName: p.text("first-name"),
  lastName: p.text("LastName"),
  email: p.text(),
  phoneNumber: p.text("phone_number"),
});
```
```sql
SELECT a.attname AS column_name, format_type(a.atttypid, a.atttypmod) as data_type FROM pg_catalog.pg_attribute a;
```
``` 
 column_name   | data_type        
---------------+------------------------
 id            | serial
 first-name    | text
 LastName      | text
 email         | text
 phone_number  | text
```
</Section>
<Section>
```ts
import * as p from "drizzle-orm/pg-core"

export const users = p.pgTable("users", {
  id: p.serial(),
  "first-name": p.text("first-name"),
  LastName: p.text("LastName"),
  email: p.text(),
  phone_number: p.text("phone_number"),
});
```
```sql
SELECT a.attname AS column_name, format_type(a.atttypid, a.atttypmod) as data_type FROM pg_catalog.pg_attribute a;
```
``` 
 column_name   | data_type        
---------------+------------------------
 id            | serial
 first-name    | text
 LastName      | text
 email         | text
 phone_number  | text
```
</Section>
</CodeTabs>


## --- 

### `tablesFilter`
<Callout>
If you want to run multiple projects with one database - check out [our guide](/docs/goodies#multi-project-schema).
</Callout>
<rem025/>
`drizzle-kit push` and `drizzle-kit pull` will by default manage all tables in `public` schema.
You can configure list of tables, schemas and extensions via `tablesFilters`, `schemaFilter` and `extensionFilters` options.

`tablesFilter` option lets you specify [`glob`](https://www.digitalocean.com/community/tools/glob?comments=true&glob=/**/*.js&matches=false&tests=//%20This%20will%20match%20as%20it%20ends%20with%20'.js'&tests=/hello/world.js&tests=//%20This%20won't%20match!&tests=/test/some/globs) 
based table names filter, e.g. `["users", "user_info"]` or `"user*"`

|               |                      |
| :------------ | :-----------------   |
| type          | `string` `string[]` |
| default       | --                    |
| commands      | `push` `pull`   |

<rem025/>
```ts
import { defineConfig } from "drizzle-kit";

export default defineConfig({
  dialect: "postgresql",
  tablesFilter: ["users", "posts", "project1_*"],
});
```

### `schemaFilter`


<Callout>
If you want to run multiple projects with one database - check out [our guide](/docs/goodies#multi-project-schema).
</Callout>

`drizzle-kit push` and `drizzle-kit pull` will by default manage all schemas.

`schemaFilter` option lets you specify [`glob`](https://www.digitalocean.com/community/tools/glob?comments=true&glob=/**/*.js&matches=false&tests=//%20This%20will%20match%20as%20it%20ends%20with%20'.js'&tests=/hello/world.js&tests=//%20This%20won't%20match!&tests=/test/some/globs) 
based schema names filter, e.g. `["public", "auth"]` or `"tenant_*"`

|               |                      |
| :------------ | :-----------------   |
| type          | `string[]` |
| commands      | `push` `pull`   |

<rem025/>

```ts
export default defineConfig({
  dialect: "postgresql",
  schemaFilter: ["public", "schema1", "schema2"],
});
```

### `extensionsFilters`
<rem025/>

Some extensions like [`postgis`](https://postgis.net/), when installed on the database, create its own tables in public schema. 
Those tables have to be ignored by `drizzle-kit push` or `drizzle-kit pull`.

`extensionsFilters` option lets you declare list of installed extensions for drizzle kit to ignore their tables in the schema.

|               |                      |
| :------------ | :-----------------   |
| type          | `["postgis"]` |
| default       | `[]`                    |
| commands      | `push` `pull`   |

<rem025/>

```ts
export default defineConfig({
  dialect: "postgresql",
  extensionsFilters: ["postgis"],
});
```

## ---

### `entities`

This configuration is created to set up management settings for specific `entities` in the database. 

For now, it only includes `roles`, but eventually all database entities will migrate here, such as `tables`, `schemas`, `extensions`, `functions`, `triggers`, etc

#### `roles`

<rem025/>

If you are using Drizzle Kit to manage your schema and especially the defined roles, there may be situations where you have some roles that are not defined in the Drizzle schema. 
In such cases, you may want Drizzle Kit to skip those `roles` without the need to write each role in your Drizzle schema and mark it with `.existing()`.

The `roles` option lets you:

- Enable or disable role management with Drizzle Kit.
- Exclude specific roles from management by Drizzle Kit.
- Include specific roles for management by Drizzle Kit.
- Enable modes for providers like `Neon` and `Supabase`, which do not manage their specific roles.
- Combine all the options above

|               |                       |
| :------------ | :-----------------    |
| type          | `boolean \| { provider: "neon" \| "supabase", include: string[], exclude: string[]}`|
| default       | `false`                  |
| commands      | `push` `pull` `generate` |

<rem025/>

By default, `drizzle-kit` won't manage roles for you, so you will need to enable that. in `drizzle.config.ts`
```ts
export default defineConfig({
  dialect: "postgresql",
  entities: {
    roles: true
  }
});
```

**You have a role `admin` and want to exclude it from the list of manageable roles**

```ts
// drizzle.config.ts
import { defineConfig } from "drizzle-kit";

export default defineConfig({
  ...
  entities: {
    roles: {
      exclude: ['admin']
    }
  }
});
```

**You have a role `admin` and want to include to the list of manageable roles**

```ts
// drizzle.config.ts
import { defineConfig } from "drizzle-kit";

export default defineConfig({
  ...
  entities: {
    roles: {
      include: ['admin']
    }
  }
});
```

**If you are using `Neon` and want to exclude roles defined by `Neon`, you can use the provider option**

```ts
// drizzle.config.ts
import { defineConfig } from "drizzle-kit";

export default defineConfig({
  ...
  entities: {
    roles: {
      provider: 'neon'
    }
  }
});
```

**If you are using `Supabase` and want to exclude roles defined by `Supabase`, you can use the provider option**

```ts
// drizzle.config.ts
import { defineConfig } from "drizzle-kit";

export default defineConfig({
  ...
  entities: {
    roles: {
      provider: 'supabase'
    }
  }
});
```

<Callout title='important'>
You may encounter situations where Drizzle is slightly outdated compared to new roles specified by database providers, 
so you may need to use both the `provider` option and `exclude` additional roles. You can easily do this with Drizzle:

```ts
// drizzle.config.ts
import { defineConfig } from "drizzle-kit";

export default defineConfig({
  ...
  entities: {
    roles: {
      provider: 'supabase',
      exclude: ['new_supabase_role']
    }
  }
});
```
</Callout>

## ---

### `verbose`
<rem025/>

Print all SQL statements during `drizzle-kit push` command.

|               |                      |
| :------------ | :-----------------   |
| type          | `boolean` |
| default       | `true`                    |
| commands      | `generate` `pull`   |

<rem025/>

```ts
export default defineConfig({
  dialect: "postgresql",
  verbose: false,
});
```

### `breakpoints`
<rem025/>

Drizzle Kit will automatically embed `--> statement-breakpoint` into generated SQL migration files, 
that's necessary for databases that do not support multiple DDL alternation statements in one transaction(MySQL and SQLite).

`breakpoints` option flag lets you switch it on and off

|               |                      |
| :------------ | :-----------------   |
| type          | `boolean` |
| default       | `true`                    |
| commands      | `generate` `pull`   |

<rem025/>

```ts
export default defineConfig({
  dialect: "postgresql",
  breakpoints: false,
});
```


Source: https://orm.drizzle.team/docs/effect-schema

import Npm from '@mdx/Npm.astro';
import Callout from '@mdx/Callout.astro';

<Callout type="error">
Drizzle+Effect Schema integration is available starting from `drizzle-orm@1.0.0-beta.15`
</Callout>

# effect-schema

Allows you to generate [effect](https://effect.website/) schemas from Drizzle ORM schemas.

**Features**

- Create a select schema for tables, views and enums.
- Create insert and update schemas for tables.
- Supported dialects: CockroachDB, MSSQL, MySQL, PostgreSQL, SingleStore, SQLite.

#### Usage

```ts
import { pgEnum, pgTable, serial, text, timestamp } from 'drizzle-orm/pg-core';
import { createInsertSchema, createSelectSchema, createUpdateSchema } from 'drizzle-orm/effect-schema';
import { Schema } from 'effect';

const users = pgTable('users', {
	id: serial('id').primaryKey(),
	name: text('name').notNull(),
	email: text('email').notNull(),
	role: text('role', { enum: ['admin', 'user'] }).notNull(),
	createdAt: timestamp('created_at').notNull().defaultNow(),
});

// Schema for inserting a user - can be used to validate API requests
const UserInsert = createInsertSchema(users);

// Schema for updating a user - can be used to validate API requests
const UserUpdate = createUpdateSchema(users);

// Schema for selecting a user - can be used to validate API responses
const UserSelect = createSelectSchema(users);

// Overriding the fields
const UserInsert = createInsertSchema(users, {
	role: Schema.String,
});

// Refining the fields - useful if you want to change the fields before they become nullable/optional in the final schema
const UserInsert = createInsertSchema(users, {
	id: (schema) => schema.pipe(Schema.greaterThanOrEqualTo(0)),
	role: Schema.String,
});

// Usage

const program = Effect.gen(function*() {
	const parsedUser = yield* Schema.validate(UserInsert)({
		name: 'John Doe',
		email: 'johndoe@test.com',
		role: 'admin',
	});
});
```

Source: https://orm.drizzle.team/docs/eslint-plugin

import Tabs from '@mdx/Tabs.astro';
import Tab from '@mdx/Tab.astro';
import Npm from '@mdx/Npm.astro';

# ESLint Drizzle Plugin

For cases where it's impossible to perform type checks for specific scenarios, or where it's possible but error messages would be challenging to understand, we've decided to create an ESLint package with recommended rules. This package aims to assist developers in handling crucial scenarios during development

## Install

<Npm>
eslint-plugin-drizzle
@typescript-eslint/eslint-plugin @typescript-eslint/parser
</Npm>

## Usage

**`.eslintrc.yml` example**
```yml
root: true
parser: '@typescript-eslint/parser'
parserOptions:
  project: './tsconfig.json'
plugins:
  - drizzle
rules:
  'drizzle/enforce-delete-with-where': "error"
  'drizzle/enforce-update-with-where': "error"
```

**All config**

This plugin exports an `all` that makes use of all rules (except for deprecated ones).

```yml
root: true
extends:
  - "plugin:drizzle/all"
parser: '@typescript-eslint/parser'
parserOptions:
  project: './tsconfig.json'
plugins:
  - drizzle
```

**Recommended config**

At the moment, `all` is equivalent to `recommended`

```yml
root: true
extends:
  - "plugin:drizzle/recommended"
parser: '@typescript-eslint/parser'
parserOptions:
  project: './tsconfig.json'
plugins:
  - drizzle
```

## Rules

### **enforce-delete-with-where**

Enforce using `delete` with the`.where()` clause in the `.delete()` statement. Most of the time, 
you don't need to delete all rows in the table and require some kind of `WHERE` statements.

Optionally, you can define a `drizzleObjectName` in the plugin options that accept a `string` or
`string[]`. This is useful when you have objects or classes with a delete method that's not from
Drizzle. Such a `delete` method will trigger the ESLint rule. To avoid that, you can define the 
name of the Drizzle object that you use in your codebase (like db) so that the rule would only 
trigger if the delete method comes from this object:

Example, config 1:
```yml
rules:
  'drizzle/enforce-delete-with-where': "error"
```

```ts
class MyClass {
  public delete() {
    return {}
  }
}

const myClassObj = new MyClass();

// ---> Will be triggered by ESLint Rule
myClassObj.delete()

const db = drizzle(...)
// ---> Will be triggered by ESLint Rule
db.delete()
```

Example, config 2:
```yml
rules:
  'drizzle/enforce-delete-with-where':
    - "error"
    - "drizzleObjectName": 
      - "db"
```
```ts
class MyClass {
  public delete() {
    return {}
  }
}

const myClassObj = new MyClass();

// ---> Will NOT be triggered by ESLint Rule
myClassObj.delete()

const db = drizzle(...)
// ---> Will be triggered by ESLint Rule
db.delete()
```

### **enforce-update-with-where**: 

Enforce using `update` with the`.where()` clause in the `.update()` statement. 
Most of the time, you don't need to update all rows in the table and require 
some kind of `WHERE` statements.

Optionally, you can define a `drizzleObjectName` in the plugin options that accept 
a `string` or `string[]`. This is useful when you have objects or classes with a delete 
method that's not from Drizzle. Such as `update` method will trigger the ESLint rule. To 
avoid that, you can define the name of the Drizzle object that you use in your codebase (like db) 
so that the rule would only trigger if the delete method comes from this object:

Example, config 1:
```yml
rules:
  'drizzle/enforce-update-with-where': "error"
```

```ts
class MyClass {
  public update() {
    return {}
  }
}

const myClassObj = new MyClass();

// ---> Will be triggered by ESLint Rule
myClassObj.update()

const db = drizzle(...)
// ---> Will be triggered by ESLint Rule
db.update()
```

Example, config 2:
```yml
rules:
  'drizzle/enforce-update-with-where':
    - "error"
    - "drizzleObjectName": 
      - "db"
```
```ts
class MyClass {
  public update() {
    return {}
  }
}

const myClassObj = new MyClass();

// ---> Will NOT be triggered by ESLint Rule
myClassObj.update()

const db = drizzle(...)
// ---> Will be triggered by ESLint Rule
db.update()
```

Source: https://orm.drizzle.team/docs/faq

import Callout from '@mdx/Callout.astro';

# FAQ & Troubleshooting

## **Should I use `generate` or `push`?**

Those are logically 2 different commands. `generate` is used to create an sql file together with additional
information needed for `drizzle-kit` (or any other migration tool).

After generating those migrations, they won't be applied to a database. 
You need to do it in the next step. You can read more about it **[here](/docs/migrations)**

On the other hand, `push` doesn't need any migrations to be generated. It will
simply sync your schema with the database schema. Please be careful when using it;
we recommend it only for local development and local databases. To read more about it, check out **[`drizzle-kit push`](/docs/drizzle-kit-push)**

## How `push` and `generate` works for PostgreSQL indexes

### Limitations

1. **You should specify a name for your index manually if you have an index on at least one expression**

Example

```ts
index().on(table.id, table.email) // will work well and name will be autogeneretaed
index('my_name').on(table.id, table.email) // will work well

// but

index().on(sql`lower(${table.email})`) // error
index('my_name').on(sql`lower(${table.email})`) // will work well
```

2. **Push won't generate statements if these fields(list below) were changed in an existing index:**

- expressions inside `.on()` and `.using()`
- `.where()` statements
- operator classes `.op()` on columns

If you are using `push` workflows and want to change these fields in the index, you would need to:

1. Comment out the index
2. Push
3. Uncomment the index and change those fields
4. Push again

For the `generate` command, `drizzle-kit` will be triggered by any changes in the index for any property in the new drizzle indexes API, so there are no limitations here.

Source: https://orm.drizzle.team/docs/get-started-gel

import Tab from '@mdx/Tab.astro';
import Tabs from '@mdx/Tabs.astro';
import Npm from "@mdx/Npm.astro";
import Callout from '@mdx/Callout.astro';
import Steps from '@mdx/Steps.astro';
import AnchorCards from '@mdx/AnchorCards.astro';
import Prerequisites from "@mdx/Prerequisites.astro";
import CodeTabs from "@mdx/CodeTabs.astro";
import WhatsNextPostgres from "@mdx/WhatsNextPostgres.astro";

# Drizzle \<\> Gel
<Prerequisites>
- Database [connection basics](/docs/connect-overview) with Drizzle
- gel-js [basics](https://github.com/geldata/gel-js)
</Prerequisites>

Drizzle has native support for Gel connections with the `gel-js` client.

#### Step 1 - Install packages
<Npm>
drizzle-orm@rc gel
-D drizzle-kit@rc
</Npm>

#### Step 2 - Initialize the driver and make a query
<CodeTabs items={["gel", "gel with config"]}>
```typescript copy
// Make sure to install the 'gel' package 
import { drizzle } from 'drizzle-orm/gel';

const db = drizzle(process.env.DATABASE_URL);
 
const result = await db.execute('select 1');
```
```typescript copy
// Make sure to install the 'gel' package
import { drizzle } from "drizzle-orm/gel";

// You can specify any property from the gel connection options
const db = drizzle({
  connection: {
    dsn: process.env.DATABASE_URL,
    tlsSecurity: "default",
  },
});

const result = await db.execute("select 1");
```
</CodeTabs>

If you need to provide your existing driver:

```typescript copy
// Make sure to install the 'gel' package 
import { drizzle } from "drizzle-orm/gel";
import { createClient } from "gel";

const gelClient = createClient();
const db = drizzle({ client: gelClient });

const result = await db.execute('select 1');
```

#### What's next?

<WhatsNextPostgres/>


Source: https://orm.drizzle.team/docs/get-started

import Callout from '@mdx/Callout.astro';
import CodeTabs from '@mdx/CodeTabs.astro';
import YoutubeCards from '@mdx/YoutubeCards.astro';
import GetStartedLinks from '@mdx/GetStartedLinks/index.astro';

# Get started with Drizzle
<GetStartedLinks />

Source: https://orm.drizzle.team/docs/get-started/appwrite-mysql-existing

import Callout from '@mdx/Callout.astro';
import Breadcrumbs from '@mdx/Breadcrumbs.astro';
import Prerequisites from "@mdx/Prerequisites.astro";
import FileStructure from '@mdx/get-started/FileStructure.mdx';
import InstallPackages from '@mdx/get-started/InstallPackages.mdx';
import ConnectAppwriteMySQL from '@mdx/get-started/mysql/ConnectAppwriteMySQL.mdx';
import UpdateSchema from '@mdx/get-started/mysql/UpdateSchema.mdx';
import IntrospectMySQL from '@mdx/get-started/mysql/IntrospectMySQL.mdx';
import QueryDatabase from '@mdx/get-started/QueryDatabase.mdx';
import QueryDatabaseUpdated from '@mdx/get-started/QueryDatabaseUpdated.mdx';
import ApplyChanges from '@mdx/get-started/mysql/ApplyChanges.mdx';
import RunFile from '@mdx/get-started/RunFile.mdx';
import SetupConfig from '@mdx/get-started/mysql/SetupConfig.mdx';
import TransferCode from '@mdx/get-started/TransferCode.mdx';

<Breadcrumbs/>

# Get Started with Drizzle and Appwrite MySQL in existing project

<Prerequisites>
  - **dotenv** - package for managing environment variables - [read here](https://www.npmjs.com/package/dotenv)
  - **tsx** - package for running TypeScript files - [read here](https://tsx.hirok.io/)
  - **Appwrite MySQL** - native MySQL database by Appwrite - [read here](https://appwrite.io/docs/products/databases/mysql)
  - **mysql2** - package for querying your MySQL database - [read here](https://github.com/sidorares/node-mysql2)
</Prerequisites>

<Callout title='Appwrite also offers PostgreSQL' type='info'>
Looking for PostgreSQL? Check out our [Appwrite Postgres guide](/docs/get-started/appwrite-postgres-existing)
</Callout>

Appwrite offers dedicated, native MySQL databases that you connect to directly over TLS. There is no Appwrite-specific driver, so this guide uses the standard `mysql2` driver through the `drizzle-orm/mysql2` package.

For detailed instructions on creating an Appwrite MySQL database, see the [Appwrite MySQL documentation](https://appwrite.io/docs/products/databases/mysql).

<FileStructure/>

#### Step 1 - Install **mysql2** package

<InstallPackages lib='mysql2'/>

#### Step 2 - Setup connection variables

Create a `.env` file in the root of your project and add your database connection variable:

```plaintext copy
DATABASE_URL=mysql://admin.<hash>:<password>@db-<hash>.<region>.appwrite.center:3306/default?ssl=true
```

<Callout title='tips'>
You can obtain your connection string from the Appwrite Console by opening your database and clicking **"Credentials"**. The username is `admin.<hash>`, where the hash matches the one in the hostname, and the database name is always `default`. Appwrite routes your connection by this username, so always use the full value from the connection string. See the [Appwrite MySQL connections guide](https://appwrite.io/docs/products/databases/mysql/connections) for detailed steps.
</Callout>

#### Step 3 - Setup Drizzle config file

<SetupConfig dialect='mysql' env_variable='DATABASE_URL'/>

#### Step 4 - Introspect your database

<IntrospectMySQL/>

#### Step 5 - Transfer code to your actual schema file

<TransferCode/>

#### Step 6 - Connect Drizzle ORM to the database

<ConnectAppwriteMySQL/>

#### Step 7 - Query the database

<QueryDatabase dialect='mysql2' env_variable='DATABASE_URL'/>

#### Step 8 - Run index.ts file

<RunFile/>

#### Step 9 - Update your table schema (optional)

<UpdateSchema/>

#### Step 10 - Applying changes to the database (optional)

<ApplyChanges/>

#### Step 11 - Query the database with a new field (optional)

<QueryDatabaseUpdated dialect='mysql2' env_variable='DATABASE_URL' />


Source: https://orm.drizzle.team/docs/get-started/appwrite-mysql-new

import Callout from '@mdx/Callout.astro';
import Breadcrumbs from '@mdx/Breadcrumbs.astro';
import Prerequisites from "@mdx/Prerequisites.astro";
import FileStructure from '@mdx/get-started/FileStructure.mdx';
import InstallPackages from '@mdx/get-started/InstallPackages.mdx';
import ConnectAppwriteMySQL from '@mdx/get-started/mysql/ConnectAppwriteMySQL.mdx';
import CreateTable from '@mdx/get-started/mysql/CreateTable.mdx';
import QueryDatabase from '@mdx/get-started/QueryDatabase.mdx';
import ApplyChanges from '@mdx/get-started/mysql/ApplyChanges.mdx';
import RunFile from '@mdx/get-started/RunFile.mdx';
import SetupConfig from '@mdx/get-started/mysql/SetupConfig.mdx';

<Breadcrumbs/>

# Get Started with Drizzle and Appwrite MySQL

<Prerequisites>
  - **dotenv** - package for managing environment variables - [read here](https://www.npmjs.com/package/dotenv)
  - **tsx** - package for running TypeScript files - [read here](https://tsx.hirok.io/)
  - **Appwrite MySQL** - native MySQL database by Appwrite - [read here](https://appwrite.io/docs/products/databases/mysql)
  - **mysql2** - package for querying your MySQL database - [read here](https://github.com/sidorares/node-mysql2)
</Prerequisites>

<Callout title='Appwrite also offers PostgreSQL' type='info'>
Looking for PostgreSQL? Check out our [Appwrite Postgres guide](/docs/get-started/appwrite-postgres-new)
</Callout>

Appwrite offers dedicated, native MySQL databases that you connect to directly over TLS. There is no Appwrite-specific driver, so this guide uses the standard `mysql2` driver through the `drizzle-orm/mysql2` package.

For detailed instructions on creating an Appwrite MySQL database, see the [Appwrite MySQL documentation](https://appwrite.io/docs/products/databases/mysql).

<FileStructure/>

#### Step 1 - Install **mysql2** package

<InstallPackages lib='mysql2'/>

#### Step 2 - Setup connection variables

Create a `.env` file in the root of your project and add your database connection variable:

```plaintext copy
DATABASE_URL=mysql://admin.<hash>:<password>@db-<hash>.<region>.appwrite.center:3306/default?ssl=true
```

<Callout title='tips'>
You can obtain your connection string from the Appwrite Console by opening your database and clicking **"Credentials"**. The username is `admin.<hash>`, where the hash matches the one in the hostname, and the database name is always `default`. Appwrite routes your connection by this username, so always use the full value from the connection string. See the [Appwrite MySQL connections guide](https://appwrite.io/docs/products/databases/mysql/connections) for detailed steps.
</Callout>

#### Step 3 - Connect Drizzle ORM to the database

<ConnectAppwriteMySQL/>

#### Step 4 - Create a table

<CreateTable/>

#### Step 5 - Setup Drizzle config file

<SetupConfig dialect='mysql' env_variable='DATABASE_URL'/>

#### Step 6 - Applying changes to the database

<ApplyChanges />

#### Step 7 - Seed and Query the database

<QueryDatabase dialect='mysql2' env_variable='DATABASE_URL'/>

#### Step 8 - Run index.ts file

<RunFile/>


Source: https://orm.drizzle.team/docs/get-started/appwrite-postgres-existing

import Callout from '@mdx/Callout.astro';
import Breadcrumbs from '@mdx/Breadcrumbs.astro';
import Prerequisites from "@mdx/Prerequisites.astro";
import IntrospectPostgreSQL from '@mdx/get-started/postgresql/IntrospectPostgreSQL.mdx';
import FileStructure from '@mdx/get-started/FileStructure.mdx';
import InstallPackages from '@mdx/get-started/InstallPackages.mdx';
import SetupConfig from '@mdx/get-started/SetupConfig.mdx';
import TransferCode from '@mdx/get-started/TransferCode.mdx';
import ApplyChanges from '@mdx/get-started/ApplyChanges.mdx';
import RunFile from '@mdx/get-started/RunFile.mdx';
import ConnectAppwritePostgres from '@mdx/get-started/postgresql/ConnectAppwritePostgres.mdx'
import QueryDatabase from '@mdx/get-started/QueryDatabase.mdx';
import QueryDatabaseUpdated from '@mdx/get-started/QueryDatabaseUpdated.mdx';
import UpdateSchema from '@mdx/get-started/postgresql/UpdateSchema.mdx';

<Breadcrumbs/>

# Get Started with Drizzle and Appwrite Postgres in existing project

<Prerequisites>
  - **dotenv** - package for managing environment variables - [read here](https://www.npmjs.com/package/dotenv)
  - **tsx** - package for running TypeScript files - [read here](https://tsx.hirok.io/)
  - **Appwrite Postgres** - native PostgreSQL database by Appwrite - [read here](https://appwrite.io/docs/products/databases/postgresql)
  - **node-postgres** - package for querying your PostgreSQL database - [read here](https://node-postgres.com/)
</Prerequisites>

<Callout title='Appwrite also offers MySQL' type='info'>
Looking for MySQL? Check out our [Appwrite MySQL guide](/docs/get-started/appwrite-mysql-existing)
</Callout>

Appwrite offers dedicated, native PostgreSQL databases that you connect to directly over TLS. There is no Appwrite-specific driver, so this guide uses the standard `node-postgres` driver.

For detailed instructions on creating an Appwrite Postgres database, see the [Appwrite PostgreSQL documentation](https://appwrite.io/docs/products/databases/postgresql).

<FileStructure/>

#### Step 1 - Install **node-postgres** package
<InstallPackages lib='pg' devlib=' @types/pg'/>

#### Step 2 - Setup connection variables

Create a `.env` file in the root of your project and add your database connection variable:

```plaintext copy
DATABASE_URL=postgresql://admin:<password>@db-<hash>.<region>.appwrite.center:5432/<database>?sslmode=require
```

<Callout title='tips'>
You can obtain your connection string from the Appwrite Console by opening your database and clicking **"Credentials"**. The **"Drizzle"**, **"DSN"** and **".env"** tabs contain a ready-to-use connection string that already includes `sslmode=require`. See the [Appwrite PostgreSQL connections guide](https://appwrite.io/docs/products/databases/postgresql/connections) for detailed steps.
</Callout>

#### Step 3 - Setup Drizzle config file

<SetupConfig dialect='postgresql' env_variable='DATABASE_URL'/>

#### Step 4 - Introspect your database

<IntrospectPostgreSQL/>

#### Step 5 - Transfer code to your actual schema file

<TransferCode/>

#### Step 6 - Connect Drizzle ORM to the database

<ConnectAppwritePostgres/>

#### Step 7 - Query the database

<QueryDatabase dialect='node-postgres' env_variable='DATABASE_URL'/>

#### Step 8 - Run index.ts file

<RunFile/>

#### Step 9 - Update your table schema (optional)

<UpdateSchema/>

#### Step 10 - Applying changes to the database (optional)

<ApplyChanges />

#### Step 11 - Query the database with a new field (optional)

<QueryDatabaseUpdated dialect='node-postgres' env_variable='DATABASE_URL' />


Source: https://orm.drizzle.team/docs/get-started/appwrite-postgres-new

import Callout from '@mdx/Callout.astro';
import Breadcrumbs from '@mdx/Breadcrumbs.astro';
import Prerequisites from "@mdx/Prerequisites.astro";
import FileStructure from '@mdx/get-started/FileStructure.mdx';
import InstallPackages from '@mdx/get-started/InstallPackages.mdx';
import ConnectAppwritePostgres from '@mdx/get-started/postgresql/ConnectAppwritePostgres.mdx'
import CreateTable from '@mdx/get-started/postgresql/CreateTable.mdx'
import SetupConfig from '@mdx/get-started/SetupConfig.mdx';
import ApplyChanges from '@mdx/get-started/ApplyChanges.mdx';
import RunFile from '@mdx/get-started/RunFile.mdx';
import QueryDatabase from '@mdx/get-started/QueryDatabase.mdx';

<Breadcrumbs/>

# Get Started with Drizzle and Appwrite Postgres

<Prerequisites>
  - **dotenv** - package for managing environment variables - [read here](https://www.npmjs.com/package/dotenv)
  - **tsx** - package for running TypeScript files - [read here](https://tsx.hirok.io/)
  - **Appwrite Postgres** - native PostgreSQL database by Appwrite - [read here](https://appwrite.io/docs/products/databases/postgresql)
  - **node-postgres** - package for querying your PostgreSQL database - [read here](https://node-postgres.com/)
</Prerequisites>

<Callout title='Appwrite also offers MySQL' type='info'>
Looking for MySQL? Check out our [Appwrite MySQL guide](/docs/get-started/appwrite-mysql-new)
</Callout>

Appwrite offers dedicated, native PostgreSQL databases that you connect to directly over TLS. There is no Appwrite-specific driver, so this guide uses the standard `node-postgres` driver.

For detailed instructions on creating an Appwrite Postgres database, see the [Appwrite PostgreSQL documentation](https://appwrite.io/docs/products/databases/postgresql).

<FileStructure/>

#### Step 1 - Install **node-postgres** package
<InstallPackages lib='pg' devlib=' @types/pg'/>

#### Step 2 - Setup connection variables

Create a `.env` file in the root of your project and add your database connection variable:

```plaintext copy
DATABASE_URL=postgresql://admin:<password>@db-<hash>.<region>.appwrite.center:5432/<database>?sslmode=require
```

<Callout title='tips'>
You can obtain your connection string from the Appwrite Console by opening your database and clicking **"Credentials"**. The **"Drizzle"**, **"DSN"** and **".env"** tabs contain a ready-to-use connection string that already includes `sslmode=require`. See the [Appwrite PostgreSQL connections guide](https://appwrite.io/docs/products/databases/postgresql/connections) for detailed steps.
</Callout>

#### Step 3 - Connect Drizzle ORM to the database

<ConnectAppwritePostgres/>

#### Step 4 - Create a table

<CreateTable />

#### Step 5 - Setup Drizzle config file

<SetupConfig dialect='postgresql' env_variable='DATABASE_URL'/>

#### Step 6 - Applying changes to the database

<ApplyChanges />

#### Step 7 - Seed and Query the database

<QueryDatabase dialect='node-postgres' env_variable='DATABASE_URL'/>

#### Step 8 - Run index.ts file

<RunFile/>


Source: https://orm.drizzle.team/docs/get-started/bun-sql-existing

import Npm from '@mdx/Npm.astro';
import Npx from '@mdx/Npx.astro';
import Callout from '@mdx/Callout.astro';
import Prerequisites from "@mdx/Prerequisites.astro";
import CodeTabs from "@mdx/CodeTabs.astro";
import WhatsNextPostgres from "@mdx/WhatsNextPostgres.astro";
import Breadcrumbs from '@mdx/Breadcrumbs.astro';
import FileStructure from '@mdx/get-started/FileStructure.mdx';
import InstallPackages from '@mdx/get-started/InstallPackages.mdx';
import SetupConfig from '@mdx/get-started/SetupConfig.mdx';
import TransferCode from '@mdx/get-started/TransferCode.mdx';
import QueryDatabase from '@mdx/get-started/QueryDatabase.mdx';
import QueryDatabaseUpdated from '@mdx/get-started/QueryDatabaseUpdated.mdx';
import RunFile from '@mdx/get-started/RunFile.mdx';
import ApplyChanges from '@mdx/get-started/ApplyChanges.mdx';
import SetupEnv from '@mdx/get-started/SetupEnv.mdx';
import IntrospectPostgreSQL from '@mdx/get-started/postgresql/IntrospectPostgreSQL.mdx';
import ConnectBun from '@mdx/get-started/postgresql/ConnectBun.mdx';
import UpdateSchema from '@mdx/get-started/postgresql/UpdateSchema.mdx';

<Breadcrumbs/>

# Get Started with Drizzle and SQLite in existing project

<Prerequisites>  
  - **dotenv** - package for managing environment variables - [read here](https://www.npmjs.com/package/dotenv)
  - **bun** - javaScript all-in-one toolkit - [read here](https://bun.sh/)
  - **Bun SQL** - native bindings for working with PostgreSQL databases - [read here](https://bun.sh/docs/api/sql)
</Prerequisites>

<Callout type='error'>
In version `1.2.0`, Bun has issues with executing concurrent statements, which may lead to errors if you try to run several queries simultaneously.
We've created a [github issue](https://github.com/oven-sh/bun/issues/16774) that you can track. Once it's fixed, you should no longer encounter any such errors on Bun's SQL side
</Callout>

<FileStructure />

#### Step 1 - Install required packages

<Npm>
    drizzle-orm@rc dotenv
    -D drizzle-kit@rc @types/bun
</Npm>

#### Step 2 - Setup connection variables

<SetupEnv env_variable='DATABASE_URL' />

#### Step 3 - Setup Drizzle config file

<SetupConfig dialect='postgresql' env_variable='DATABASE_URL'/>

#### Step 4 - Introspect your database

<IntrospectPostgreSQL/>

#### Step 5 - Transfer code to your actual schema file

<TransferCode/>

#### Step 6 - Connect Drizzle ORM to the database

<ConnectBun/>

#### Step 7 - Query the database

<QueryDatabase dialect='bun-sql' env_variable='DATABASE_URL' />

#### Step 8 - Run index.ts file

To run a script with `bun`, use the following command:
```bash copy
bun src/index.ts
```

#### Step 9 - Update your table schema (optional)

<UpdateSchema/>

#### Step 9 - Applying changes to the database (optional)

<ApplyChanges/>

#### Step 10 - Query the database with a new field (optional)

<QueryDatabaseUpdated dialect='bun-sql' env_variable='DATABASE_URL' />


Source: https://orm.drizzle.team/docs/get-started/bun-sql-new

import Npm from '@mdx/Npm.astro';
import Npx from '@mdx/Npx.astro';
import Callout from '@mdx/Callout.astro';
import Prerequisites from "@mdx/Prerequisites.astro";
import CodeTabs from "@mdx/CodeTabs.astro";
import WhatsNextPostgres from "@mdx/WhatsNextPostgres.astro";
import Breadcrumbs from '@mdx/Breadcrumbs.astro';
import FileStructure from '@mdx/get-started/FileStructure.mdx';
import InstallPackages from '@mdx/get-started/InstallPackages.mdx';
import SetupConfig from '@mdx/get-started/SetupConfig.mdx';
import TransferCode from '@mdx/get-started/TransferCode.mdx';
import QueryDatabase from '@mdx/get-started/QueryDatabase.mdx';
import QueryDatabaseUpdated from '@mdx/get-started/QueryDatabaseUpdated.mdx';
import RunFile from '@mdx/get-started/RunFile.mdx';
import ApplyChanges from '@mdx/get-started/ApplyChanges.mdx';
import SetupEnv from '@mdx/get-started/SetupEnv.mdx';
import CreateTable from '@mdx/get-started/postgresql/CreateTable.mdx';
import ConnectBun from '@mdx/get-started/postgresql/ConnectBun.mdx';

<Breadcrumbs/>

# Get Started with Drizzle and Bun:SQLite

<Prerequisites>  
  - **bun** - javaScript all-in-one toolkit - [read here](https://bun.sh/)
  - **Bun SQL** - native bindings for working with PostgreSQL databases - [read here](https://bun.sh/docs/api/sql)
</Prerequisites>

<Callout type='error'>
In version `1.2.0`, Bun has issues with executing concurrent statements, which may lead to errors if you try to run several queries simultaneously.
We've created a [github issue](https://github.com/oven-sh/bun/issues/16774) that you can track. Once it's fixed, you should no longer encounter any such errors on Bun's SQL side
</Callout>

<FileStructure />

#### Step 1 - Install required packages
<Npm>
    drizzle-orm@rc
    -D drizzle-kit@rc @types/bun
</Npm>

#### Step 2 - Setup connection variables

<SetupEnv env_variable='DATABASE_URL' />

#### Step 3 - Connect Drizzle ORM to the database

<ConnectBun/>

#### Step 4 - Create a table

<CreateTable/>

#### Step 5 - Setup Drizzle config file

<SetupConfig dialect='postgresql' env_variable='DATABASE_URL'/>

#### Step 6 - Applying changes to the database

<ApplyChanges />

#### Step 7 - Seed and Query the database

<QueryDatabase dialect='bun-sql' env_variable='DATABASE_URL'/>

#### Step 8 - Run index.ts file

To run a script with `bun`, use the following command:
```bash copy
bun src/index.ts
```


Source: https://orm.drizzle.team/docs/get-started/bun-sqlite-existing

import Npm from '@mdx/Npm.astro';
import Npx from '@mdx/Npx.astro';
import Callout from '@mdx/Callout.astro';
import Prerequisites from "@mdx/Prerequisites.astro";
import CodeTabs from "@mdx/CodeTabs.astro";
import WhatsNextPostgres from "@mdx/WhatsNextPostgres.astro";
import Breadcrumbs from '@mdx/Breadcrumbs.astro';
import FileStructure from '@mdx/get-started/FileStructure.mdx';
import InstallPackages from '@mdx/get-started/InstallPackages.mdx';
import SetupConfig from '@mdx/get-started/sqlite/SetupConfig.mdx';
import TransferCode from '@mdx/get-started/TransferCode.mdx';
import QueryDatabase from '@mdx/get-started/QueryDatabase.mdx';
import QueryDatabaseUpdated from '@mdx/get-started/QueryDatabaseUpdated.mdx';
import RunFile from '@mdx/get-started/RunFile.mdx';
import ApplyChanges from '@mdx/get-started/sqlite/ApplyChanges.mdx';
import SetupEnv from '@mdx/get-started/SetupEnv.mdx';
import IntrospectSqlite from '@mdx/get-started/sqlite/IntrospectSqlite.mdx';
import ConnectBun from '@mdx/get-started/sqlite/ConnectBun.mdx';
import UpdateSchema from '@mdx/get-started/sqlite/UpdateSchema.mdx';

<Breadcrumbs/>

# Get Started with Drizzle and Bun:SQLite in existing project

<Prerequisites>  
  - **dotenv** - package for managing environment variables - [read here](https://www.npmjs.com/package/dotenv)
  - **tsx** - package for running TypeScript files - [read here](https://tsx.hirok.io/)
  - **bun** - javaScript all-in-one toolkit - [read here](https://bun.sh/)
  - **bun:sqlite** - native implementation of a high-performance SQLite3 driver - [read here](https://bun.sh/docs/api/sqlite)
</Prerequisites>

<FileStructure />

#### Step 1 - Install required packages

<Npm>
    drizzle-orm@rc dotenv
    -D drizzle-kit@rc tsx @types/bun
</Npm>

#### Step 2 - Setup connection variables

<SetupEnv env_variable='DB_FILE_NAME' />

<Callout type='info' title='important'>
For example, if you have an SQLite database file in the root of your project, you can use this example:
```plaintext copy
DB_FILE_NAME=mydb.sqlite
```
</Callout>


#### Step 3 - Setup Drizzle config file

<SetupConfig dialect='sqlite' env_variable='DB_FILE_NAME'/>

#### Step 4 - Introspect your database

<IntrospectSqlite/>

#### Step 5 - Transfer code to your actual schema file

<TransferCode/>

#### Step 6 - Connect Drizzle ORM to the database

<ConnectBun/>

#### Step 7 - Query the database

<QueryDatabase dialect='bun-sqlite' env_variable='DB_FILE_NAME' />

#### Step 8 - Run index.ts file

To run a script with `bun`, use the following command:
```bash copy
bun src/index.ts
```

#### Step 9 - Update your table schema (optional)

<UpdateSchema/>

#### Step 9 - Applying changes to the database (optional)

<ApplyChanges/>

#### Step 10 - Query the database with a new field (optional)

<QueryDatabaseUpdated dialect='bun-sqlite' env_variable='DB_FILE_NAME' />


Source: https://orm.drizzle.team/docs/get-started/bun-sqlite-new

import Npm from '@mdx/Npm.astro';
import Npx from '@mdx/Npx.astro';
import Callout from '@mdx/Callout.astro';
import Prerequisites from "@mdx/Prerequisites.astro";
import CodeTabs from "@mdx/CodeTabs.astro";
import WhatsNextPostgres from "@mdx/WhatsNextPostgres.astro";
import Breadcrumbs from '@mdx/Breadcrumbs.astro';
import FileStructure from '@mdx/get-started/FileStructure.mdx';
import InstallPackages from '@mdx/get-started/InstallPackages.mdx';
import SetupConfig from '@mdx/get-started/sqlite/SetupConfig.mdx';
import TransferCode from '@mdx/get-started/TransferCode.mdx';
import QueryDatabase from '@mdx/get-started/QueryDatabase.mdx';
import QueryDatabaseUpdated from '@mdx/get-started/QueryDatabaseUpdated.mdx';
import RunFile from '@mdx/get-started/RunFile.mdx';
import ApplyChanges from '@mdx/get-started/sqlite/ApplyChanges.mdx';
import SetupEnv from '@mdx/get-started/SetupEnv.mdx';
import CreateTable from '@mdx/get-started/sqlite/CreateTable.mdx';
import ConnectBun from '@mdx/get-started/sqlite/ConnectBun.mdx';

<Breadcrumbs/>

# Get Started with Drizzle and Bun:SQLite

<Prerequisites>  
  - **bun** - javaScript all-in-one toolkit - [read here](https://bun.sh/)
  - **bun:sqlite** - native implementation of a high-performance SQLite3 driver - [read here](https://bun.sh/docs/api/sqlite)
</Prerequisites>

<FileStructure />

#### Step 1 - Install required packages
<Npm>
    drizzle-orm@rc
    -D drizzle-kit@rc @types/bun
</Npm>

#### Step 2 - Setup connection variables

<SetupEnv env_variable='DB_FILE_NAME' />

<Callout type='info' title='important'>
For example, if you want to create an SQLite database file in the root of your project for testing purposes, you can use this example:
```plaintext copy
DB_FILE_NAME=mydb.sqlite
```
</Callout>

#### Step 3 - Connect Drizzle ORM to the database

<ConnectBun/>

#### Step 4 - Create a table

<CreateTable/>

#### Step 5 - Setup Drizzle config file

<SetupConfig dialect='sqlite' env_variable='DB_FILE_NAME'/>

#### Step 6 - Applying changes to the database

<ApplyChanges />

#### Step 7 - Seed and Query the database

<QueryDatabase dialect='bun-sqlite' env_variable='DB_FILE_NAME'/>

#### Step 8 - Run index.ts file

To run a script with `bun`, use the following command:
```bash copy
bun src/index.ts
```


Source: https://orm.drizzle.team/docs/get-started/cockroach-existing

import Tab from '@mdx/Tab.astro';
import Tabs from '@mdx/Tabs.astro';
import Npm from "@mdx/Npm.astro";
import Callout from '@mdx/Callout.astro';
import Steps from '@mdx/Steps.astro';
import AnchorCards from '@mdx/AnchorCards.astro';
import Breadcrumbs from '@mdx/Breadcrumbs.astro';
import CodeTabs from "@mdx/CodeTabs.astro";
import Prerequisites from "@mdx/Prerequisites.astro";
import IntrospectCockroach from '@mdx/get-started/cockroach/IntrospectCockroach.mdx';
import FileStructure from '@mdx/get-started/FileStructure.mdx';
import InstallPackages from '@mdx/get-started/InstallPackages.mdx';
import SetupConfig from '@mdx/get-started/cockroach/SetupConfig.mdx';
import SetupEnv from '@mdx/get-started/SetupEnv.mdx';
import TransferCode from '@mdx/get-started/TransferCode.mdx';
import ApplyChanges from '@mdx/get-started/cockroach/ApplyChanges.mdx';
import RunFile from '@mdx/get-started/RunFile.mdx';
import ConnectCockroach from '@mdx/get-started/cockroach/ConnectCockroach.mdx'
import QueryDatabase from '@mdx/get-started/QueryDatabase.mdx';
import QueryDatabaseUpdated from '@mdx/get-started/QueryDatabaseUpdated.mdx';
import UpdateSchema from '@mdx/get-started/cockroach/UpdateSchema.mdx';

<Breadcrumbs/>

# Get Started with Drizzle and CockroachDB in existing project

<br/>

<Prerequisites>
  - **dotenv** - package for managing environment variables - [read here](https://www.npmjs.com/package/dotenv)
  - **tsx** - package for running TypeScript files - [read here](https://tsx.hirok.io/)
  - **node-postgres** - package for querying your PostgreSQL database - [read here](https://node-postgres.com/)
</Prerequisites>

<FileStructure/>

#### Step 1 - Install **node-postgres** package
<Npm>
    drizzle-orm@rc pg dotenv
    -D drizzle-kit@rc tsx @types/pg
</Npm>


#### Step 2 - Setup connection variables

<SetupEnv env_variable='DATABASE_URL' />

#### Step 3 - Setup Drizzle config file

<SetupConfig dialect='cockroach' env_variable='DATABASE_URL'/>

#### Step 4 - Introspect your database

<IntrospectCockroach/>

#### Step 5 - Transfer code to your actual schema file

<TransferCode/>

#### Step 6 - Connect Drizzle ORM to the database

<ConnectCockroach/>

#### Step 7 - Query the database

<QueryDatabase dialect='cockroach' env_variable='DATABASE_URL'/>

#### Step 8 - Run index.ts file

<RunFile/>

#### Step 9 - Update your table schema (optional)

<UpdateSchema/>

#### Step 10 - Applying changes to the database (optional)

<ApplyChanges />

#### Step 11 - Query the database with a new field (optional)

<QueryDatabaseUpdated dialect='cockroach' env_variable='DATABASE_URL' />


Source: https://orm.drizzle.team/docs/get-started/cockroach-new

import Tab from '@mdx/Tab.astro';
import Tabs from '@mdx/Tabs.astro';
import Npm from "@mdx/Npm.astro";
import Callout from '@mdx/Callout.astro';
import Steps from '@mdx/Steps.astro';
import AnchorCards from '@mdx/AnchorCards.astro';
import Breadcrumbs from '@mdx/Breadcrumbs.astro';
import Prerequisites from "@mdx/Prerequisites.astro";
import CodeTabs from "@mdx/CodeTabs.astro";
import FileStructure from '@mdx/get-started/FileStructure.mdx';
import InstallPackages from '@mdx/get-started/InstallPackages.mdx';
import ConnectCockroach from '@mdx/get-started/cockroach/ConnectCockroach.mdx'
import CreateTable from '@mdx/get-started/cockroach/CreateTable.mdx'
import SetupConfig from '@mdx/get-started/cockroach/SetupConfig.mdx';
import ApplyChanges from '@mdx/get-started/cockroach/ApplyChanges.mdx';
import RunFile from '@mdx/get-started/RunFile.mdx';
import QueryDatabase from '@mdx/get-started/QueryDatabase.mdx';
import SetupEnv from '@mdx/get-started/SetupEnv.mdx';

<Breadcrumbs/>

# Get Started with Drizzle and CockroachDB

<br/>

<Prerequisites>
  - **dotenv** - package for managing environment variables - [read here](https://www.npmjs.com/package/dotenv)
  - **tsx** - package for running TypeScript files - [read here](https://tsx.hirok.io/)
  - **node-postgres** - package for querying your Cockroach database - [read here](https://node-postgres.com/)
</Prerequisites>

Drizzle has native support for CockroachDB connections with the `node-postgres` and `postgres.js` drivers.

We will use `node-postgres` for this get started example. But if you want to find more ways to connect to postgresql check
our [CockroachDB Connection](/docs/cockroach/get-started-cockroach) page 

<FileStructure/>

#### Step 1 - Install **node-postgres** package
<Npm>
    drizzle-orm@rc pg dotenv
    -D drizzle-kit@rc tsx @types/pg
</Npm>

#### Step 2 - Setup connection variables

<SetupEnv env_variable='DATABASE_URL' />

#### Step 3 - Connect Drizzle ORM to the database

<ConnectCockroach/>

#### Step 4 - Create a table

<CreateTable />

#### Step 5 - Setup Drizzle config file

<SetupConfig dialect='cockroach' env_variable='DATABASE_URL'/>

#### Step 6 - Applying changes to the database

<ApplyChanges />

#### Step 7 - Seed and Query the database

<QueryDatabase dialect='cockroach' env_variable='DATABASE_URL'/>

#### Step 8 - Run index.ts file

<RunFile/>


Source: https://orm.drizzle.team/docs/get-started/d1-existing

import Tab from '@mdx/Tab.astro';
import Tabs from '@mdx/Tabs.astro';
import Npm from "@mdx/Npm.astro";
import Callout from '@mdx/Callout.astro';
import Steps from '@mdx/Steps.astro';
import AnchorCards from '@mdx/AnchorCards.astro';
import Breadcrumbs from '@mdx/Breadcrumbs.astro';
import CodeTabs from "@mdx/CodeTabs.astro";
import Prerequisites from "@mdx/Prerequisites.astro";
import IntrospectSQLite from '@mdx/get-started/sqlite/IntrospectSqlite.mdx';
import FileStructure from '@mdx/get-started/FileStructure.mdx';
import InstallPackages from '@mdx/get-started/InstallPackages.mdx';
import SetupConfig from '@mdx/get-started/sqlite/SetupConfig.mdx';
import SetupEnv from '@mdx/get-started/SetupEnv.mdx';
import TransferCode from '@mdx/get-started/TransferCode.mdx';
import ApplyChanges from '@mdx/get-started/sqlite/ApplyChanges.mdx';
import RunFile from '@mdx/get-started/RunFile.mdx';
import ConnectSQLiteCloud from '@mdx/get-started/sqlite/ConnectSQLiteCloud.mdx';
import QueryDatabase from '@mdx/get-started/QueryDatabase.mdx';
import QueryDatabaseUpdated from '@mdx/get-started/QueryDatabaseUpdated.mdx';
import UpdateSchema from '@mdx/get-started/sqlite/UpdateSchema.mdx';

<Breadcrumbs/>

# Get Started with Drizzle and D1 in existing project

<Prerequisites>
  - **dotenv** - package for managing environment variables - [read here](https://www.npmjs.com/package/dotenv)
  - **tsx** - package for running TypeScript files - [read here](https://tsx.hirok.io/)
  - **Cloudflare D1** - Serverless SQL database to query from your Workers and Pages projects - [read here](https://developers.cloudflare.com/d1/)
  - **wrangler** - Cloudflare Developer Platform command-line interface - [read here](https://developers.cloudflare.com/workers/wrangler)
</Prerequisites>

<FileStructure/>

#### Step 1 - Install required package
<InstallPackages lib=''/>

#### Step 2 - Setup wrangler.toml

You would need to have a `wrangler.toml` file for D1 database and will look something like this:
```toml
name = "YOUR PROJECT NAME"
main = "src/index.ts"
compatibility_date = "2022-11-07"
node_compat = true

[[ d1_databases ]]
binding = "DB"
database_name = "YOUR DB NAME"
database_id = "YOUR DB ID"
migrations_dir = "drizzle"
```

#### Step 3 - Setup Drizzle config file

**Drizzle config** - a configuration file that is used by [Drizzle Kit](/docs/kit-overview) and contains all the information about your database connection, migration folder and schema files.

Create a `drizzle.config.ts` file in the root of your project and add the following content:

```typescript copy filename="drizzle.config.ts"
import 'dotenv/config';
import { defineConfig } from 'drizzle-kit';

export default defineConfig({
  out: './drizzle',
  schema: './src/db/schema.ts',
  dialect: 'sqlite',
  driver: 'd1-http',
  dbCredentials: {
    accountId: process.env.CLOUDFLARE_ACCOUNT_ID!,
    databaseId: process.env.CLOUDFLARE_DATABASE_ID!,
    token: process.env.CLOUDFLARE_D1_TOKEN!,
  },
});
```
<Callout title='tips'>
You can check [our tutorial](/docs/guides/d1-http-with-drizzle-kit) on how to get env variables from CloudFlare
</Callout>

#### Step 4 - Introspect your database

<IntrospectSQLite/>

#### Step 5 - Transfer code to your actual schema file

<TransferCode/>

#### Step 6 - Connect Drizzle ORM to the database

```typescript copy
import { drizzle } from 'drizzle-orm/d1';

export interface Env {
  <BINDING_NAME>: D1Database;
}
export default {
  async fetch(request: Request, env: Env) {
    const db = drizzle(env.<BINDING_NAME>);
  },
};
```

#### Step 7 - Query the database

```typescript copy
import { drizzle } from 'drizzle-orm/d1';

export interface Env {
  <BINDING_NAME>: D1Database;
}
export default {
  async fetch(request: Request, env: Env) {
    const db = drizzle(env.<BINDING_NAME>);

    const user: typeof usersTable.$inferInsert = {
      name: 'John',
      age: 30,
      email: 'john@example.com',
    };

    await db.insert(usersTable).values(user);
    console.log('New user created!');

    const users = await db.select().from(usersTable);
    console.log('Getting all users from the database: ', users);
    /*
    const users: {
      id: number;
      name: string;
      age: number;
      email: string;
    }[]
    */

    await db
      .update(usersTable)
      .set({
        age: 31,
      })
      .where(eq(usersTable.email, user.email));
    console.log('User info updated!');

    await db.delete(usersTable).where(eq(usersTable.email, user.email));
    console.log('User deleted!');

    return Response.json(users);
  },
};
```

#### Step 8 - Run index.ts file

<RunFile/>

#### Step 9 - Update your table schema (optional)

<UpdateSchema/>

#### Step 10 - Applying changes to the database (optional)

<ApplyChanges />

#### Step 11 - Query the database with a new field (optional)

```typescript copy filename="src/index.ts"
import 'dotenv/config';
import { eq } from 'drizzle-orm';
import { drizzle } from 'drizzle-orm/sqlite-cloud';
import { usersTable } from './db/schema';

async function main() {
  const db = drizzle(env.<BINDING_NAME>);

  const user: typeof usersTable.$inferInsert = {
    name: 'John',
    age: 30,
    email: 'john@example.com',
    phone: '123-456-7890',
  };

  await db.insert(usersTable).values(user);
  console.log('New user created!');

  const users = await db.select().from(usersTable);
  console.log('Getting all users from the database: ', users);
  /*
  const users: {
    id: number;
    name: string;
    age: number;
    email: string;
    phone: string | null;
  }[]
  */

  await db
    .update(usersTable)
    .set({
      age: 31,
    })
    .where(eq(usersTable.email, user.email));
  console.log('User info updated!');

  await db.delete(usersTable).where(eq(usersTable.email, user.email));
  console.log('User deleted!');

  return Response.json(users);
}

main();
```

Source: https://orm.drizzle.team/docs/get-started/d1-new

import Npm from '@mdx/Npm.astro';
import Npx from '@mdx/Npx.astro';
import Callout from '@mdx/Callout.astro';
import Prerequisites from "@mdx/Prerequisites.astro";
import CodeTabs from "@mdx/CodeTabs.astro";
import WhatsNextPostgres from "@mdx/WhatsNextPostgres.astro";
import Breadcrumbs from '@mdx/Breadcrumbs.astro';
import FileStructure from '@mdx/get-started/FileStructure.mdx';
import InstallPackages from '@mdx/get-started/InstallPackages.mdx';
import SetupConfig from '@mdx/get-started/sqlite/SetupConfig.mdx';
import TransferCode from '@mdx/get-started/TransferCode.mdx';
import QueryTurso from '@mdx/get-started/sqlite/QueryTurso.mdx';
import QueryDatabaseUpdated from '@mdx/get-started/QueryDatabaseUpdated.mdx';
import RunFile from '@mdx/get-started/RunFile.mdx';
import ApplyChanges from '@mdx/get-started/sqlite/ApplyChanges.mdx';
import SetupEnv from '@mdx/get-started/SetupEnv.mdx';
import CreateTable from '@mdx/get-started/sqlite/CreateTable.mdx';
import ConnectLibsql from '@mdx/get-started/sqlite/ConnectLibsql.mdx';

<Breadcrumbs/>

# Get Started with Drizzle and D1

<Prerequisites>  
  - **dotenv** - package for managing environment variables - [read here](https://www.npmjs.com/package/dotenv)
  - **tsx** - package for running TypeScript files - [read here](https://tsx.hirok.io/)
  - **Cloudflare D1** - Serverless SQL database to query from your Workers and Pages projects - [read here](https://developers.cloudflare.com/d1/)
  - **wrangler** - Cloudflare Developer Platform command-line interface - [read here](https://developers.cloudflare.com/workers/wrangler)
</Prerequisites>

<FileStructure />

#### Step 1 - Install required packages
<InstallPackages lib='wrangler'/>

#### Step 2 - Setup wrangler.toml

You would need to have a `wrangler.toml` file for D1 database and will look something like this:
```toml
name = "YOUR PROJECT NAME"
main = "src/index.ts"
compatibility_date = "2022-11-07"
node_compat = true

[[ d1_databases ]]
binding = "DB"
database_name = "YOUR DB NAME"
database_id = "YOUR DB ID"
migrations_dir = "drizzle"
```

#### Step 3 - Connect Drizzle ORM to the database

```typescript copy
import { drizzle } from 'drizzle-orm/d1';

export interface Env {
  <BINDING_NAME>: D1Database;
}
export default {
  async fetch(request: Request, env: Env) {
    const db = drizzle(env.<BINDING_NAME>);
  },
};
```

#### Step 4 - Generate wrangler types 

<Npx>
wrangler types
</Npx>

<Callout>
The output of this command will be a `worker-configuration.d.ts` file.
</Callout>

#### Step 5 - Create a table

<CreateTable/>

#### Step 6 - Setup Drizzle config file

**Drizzle config** - a configuration file that is used by [Drizzle Kit](/docs/kit-overview) and contains all the information about your database connection, migration folder and schema files.

Create a `drizzle.config.ts` file in the root of your project and add the following content:

```typescript copy filename="drizzle.config.ts"
import 'dotenv/config';
import { defineConfig } from 'drizzle-kit';

export default defineConfig({
  out: './drizzle',
  schema: './src/db/schema.ts',
  dialect: 'sqlite',
  driver: 'd1-http',
  dbCredentials: {
    accountId: process.env.CLOUDFLARE_ACCOUNT_ID!,
    databaseId: process.env.CLOUDFLARE_DATABASE_ID!,
    token: process.env.CLOUDFLARE_D1_TOKEN!,
  },
});
```
<Callout title='tips'>
You can check [our tutorial](/docs/guides/d1-http-with-drizzle-kit) on how to get env variables from CloudFlare
</Callout>

#### Step 7 - Applying changes to the database

<ApplyChanges />

#### Step 8 - Seed and Query the database

```typescript copy
import { drizzle } from 'drizzle-orm/d1';

export interface Env {
  <BINDING_NAME>: D1Database;
}
export default {
  async fetch(request: Request, env: Env) {
    const db = drizzle(env.<BINDING_NAME>);
    const result = await db.select().from(users).all()
    return Response.json(result);
  },
};
```

#### Step 9 - Run index.ts file

<RunFile/>

Source: https://orm.drizzle.team/docs/get-started/do-existing

import Tab from '@mdx/Tab.astro';
import Tabs from '@mdx/Tabs.astro';
import Npm from "@mdx/Npm.astro";
import Callout from '@mdx/Callout.astro';
import Steps from '@mdx/Steps.astro';
import AnchorCards from '@mdx/AnchorCards.astro';
import Breadcrumbs from '@mdx/Breadcrumbs.astro';
import CodeTabs from "@mdx/CodeTabs.astro";
import Prerequisites from "@mdx/Prerequisites.astro";
import IntrospectSQLite from '@mdx/get-started/sqlite/IntrospectSqlite.mdx';
import FileStructure from '@mdx/get-started/FileStructure.mdx';
import InstallPackages from '@mdx/get-started/InstallPackages.mdx';
import SetupConfig from '@mdx/get-started/sqlite/SetupConfig.mdx';
import SetupEnv from '@mdx/get-started/SetupEnv.mdx';
import TransferCode from '@mdx/get-started/TransferCode.mdx';
import ApplyChanges from '@mdx/get-started/sqlite/ApplyChanges.mdx';
import RunFile from '@mdx/get-started/RunFile.mdx';
import ConnectSQLiteCloud from '@mdx/get-started/sqlite/ConnectSQLiteCloud.mdx';
import QueryDatabase from '@mdx/get-started/QueryDatabase.mdx';
import QueryDatabaseUpdated from '@mdx/get-started/QueryDatabaseUpdated.mdx';
import UpdateSchema from '@mdx/get-started/sqlite/UpdateSchema.mdx';

<Breadcrumbs/>

# Get Started with Drizzle and SQLite Durable Objects in existing project

<Prerequisites>
  - **dotenv** - package for managing environment variables - [read here](https://www.npmjs.com/package/dotenv)
  - **tsx** - package for running TypeScript files - [read here](https://tsx.hirok.io/)
  - **Cloudflare SQLite Durable Objects** - SQLite database embedded within a Durable Object - [read here](https://developers.cloudflare.com/durable-objects/api/sql-storage/)
  - **wrangler** - Cloudflare Developer Platform command-line interface - [read here](https://developers.cloudflare.com/workers/wrangler)
</Prerequisites>

<FileStructure/>

#### Step 1 - Install required package
<InstallPackages lib=''/>

#### Step 2 - Setup wrangler.toml

You would need to have a `wrangler.toml` file for D1 database and will look something like this:
```toml
#:schema node_modules/wrangler/config-schema.json
name = "sqlite-durable-objects"
main = "src/index.ts"
compatibility_date = "2024-11-12"
compatibility_flags = [ "nodejs_compat" ]

# Bind a Durable Object. Durable objects are a scale-to-zero compute primitive based on the actor model.
# Durable Objects can live for as long as needed. Use these when you need a long-running "server", such as in realtime apps.
# Docs: https://developers.cloudflare.com/workers/wrangler/configuration/#durable-objects
[[durable_objects.bindings]]
name = "MY_DURABLE_OBJECT"
class_name = "MyDurableObject"

# Durable Object migrations.
# Docs: https://developers.cloudflare.com/workers/wrangler/configuration/#migrations
[[migrations]]
tag = "v1"
new_sqlite_classes = ["MyDurableObject"]

# We need rules so we can import migrations in the next steps
[[rules]] 
type = "Text"
globs = ["**/*.sql"]
fallthrough = true
```

#### Step 3 - Setup Drizzle config file

**Drizzle config** - a configuration file that is used by [Drizzle Kit](/docs/kit-overview) and contains all the information about your database connection, migration folder and schema files.

Create a `drizzle.config.ts` file in the root of your project and add the following content:

```typescript copy filename="drizzle.config.ts"
import 'dotenv/config';
import { defineConfig } from 'drizzle-kit';

export default defineConfig({
  out: './drizzle',
  schema: './src/db/schema.ts',
  dialect: 'sqlite',
  driver: 'durable-sqlite',
});
```
<Callout title='tips'>
You can check [our tutorial](/docs/guides/d1-http-with-drizzle-kit) on how to get env variables from CloudFlare
</Callout>

#### Step 4 - Introspect your database

<IntrospectSQLite/>

#### Step 5 - Transfer code to your actual schema file

<TransferCode/>

#### Step 6 - Connect Drizzle ORM to the database

```typescript copy
import { drizzle, type DrizzleSqliteDODatabase } from 'drizzle-orm/durable-sqlite';
import { DurableObject } from 'cloudflare:workers'

export class MyDurableObject extends DurableObject {
	storage: DurableObjectStorage;
	db: DrizzleSqliteDODatabase;

	constructor(ctx: DurableObjectState, env: Env) {
		super(ctx, env);
		this.storage = ctx.storage;
		this.db = drizzle(this.storage, { logger: false });
	}
}
```

#### Step 7 - Query the database

```typescript copy
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 MyDurableObject 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 });

    // Make sure all migrations complete before accepting queries.
    // Otherwise you will need to run `this.migrate()` in any function
    // that accesses the Drizzle database `this.db`.
    ctx.blockConcurrencyWhile(async () => {
      await this._migrate();
    });
  }

  async insertAndList(user: typeof usersTable.$inferInsert) {
    await this.insert(user);
    return this.select();
  }

  async insert(user: typeof usersTable.$inferInsert) {
    await this.db.insert(usersTable).values(user);
  }

  async select() {
    return this.db.select().from(usersTable);
  }

  async _migrate() {
    migrate(this.db, migrations);
  }
}

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_OBJECT.idFromName('durable-object');
    const stub = env.MY_DURABLE_OBJECT.get(id);

    // Option A - Maximum performance.
    // Prefer to bundle all the database interaction within a single Durable Object call
    // for maximum performance, since database access is fast within a DO.
    const usersAll = await stub.insertAndList({
      name: 'John',
      age: 30,
      email: 'john@example.com',
    });
    console.log('New user created. Getting all users from the database: ', users);
    /*
    const users: {
      id: number;
      name: string;
      age: number;
      email: string;
      phone: string | null;
    }[]
    */

    // Option B - Slow but maybe useful sometimes for debugging.
    // You can also directly call individual Drizzle queries if they are exposed
    // but keep in mind every query is a round-trip to the Durable Object instance.
    await stub.insert({
      name: 'John',
      age: 30,
      email: 'john@example.com',
    });
    console.log('New user created!');

    const users = await stub.select();
    console.log('Getting all users from the database: ', users);
    /*
    const users: {
      id: number;
      name: string;
      age: number;
      email: string;
      phone: string | null;
    }[]
    */

    return Response.json(users);
  }
}
```

#### Step 8 - Run index.ts file

<RunFile/>

#### Step 9 - Update your table schema (optional)

<UpdateSchema/>

#### Step 10 - Applying changes to the database (optional)

<ApplyChanges />

#### Step 11 - Query the database with a new field (optional)

```typescript copy filename="src/index.ts"
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 MyDurableObject 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 });

    // Make sure all migrations complete before accepting queries.
    // Otherwise you will need to run `this.migrate()` in any function
    // that accesses the Drizzle database `this.db`.
    ctx.blockConcurrencyWhile(async () => {
      await this._migrate();
    });
  }

  async insertAndList(user: typeof usersTable.$inferInsert) {
    await this.insert(user);
    return this.select();
  }

  async insert(user: typeof usersTable.$inferInsert) {
    await this.db.insert(usersTable).values(user);
  }

  async select() {
    return this.db.select().from(usersTable);
  }

  async _migrate() {
    migrate(this.db, migrations);
  }
}

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_OBJECT.idFromName('durable-object');
    const stub = env.MY_DURABLE_OBJECT.get(id);

    // Option A - Maximum performance.
    // Prefer to bundle all the database interaction within a single Durable Object call
    // for maximum performance, since database access is fast within a DO.
    const usersAll = await stub.insertAndList({
      name: 'John',
      age: 30,
      email: 'john@example.com',
      phone: '123-456-7890',
    });
    console.log('New user created. Getting all users from the database: ', users);
    /*
    const users: {
      id: number;
      name: string;
      age: number;
      email: string;
      phone: string | null;
    }[]
    */

    // Option B - Slow but maybe useful sometimes for debugging.
    // You can also directly call individual Drizzle queries if they are exposed
    // but keep in mind every query is a round-trip to the Durable Object instance.
    await stub.insert({
      name: 'John',
      age: 30,
      email: 'john@example.com',
      phone: '123-456-7890',
    });
    console.log('New user created!');

    const users = await stub.select();
    console.log('Getting all users from the database: ', users);
    /*
    const users: {
      id: number;
      name: string;
      age: number;
      email: string;
      phone: string | null;
    }[]
    */

    return Response.json(users);
  }
}
```

Source: https://orm.drizzle.team/docs/get-started/do-new

import Npm from '@mdx/Npm.astro';
import Npx from '@mdx/Npx.astro';
import Callout from '@mdx/Callout.astro';
import Prerequisites from "@mdx/Prerequisites.astro";
import CodeTabs from "@mdx/CodeTabs.astro";
import WhatsNextPostgres from "@mdx/WhatsNextPostgres.astro";
import Breadcrumbs from '@mdx/Breadcrumbs.astro';
import FileStructure from '@mdx/get-started/FileStructure.mdx';
import InstallPackages from '@mdx/get-started/InstallPackages.mdx';
import SetupConfig from '@mdx/get-started/sqlite/SetupConfig.mdx';
import TransferCode from '@mdx/get-started/TransferCode.mdx';
import QueryTurso from '@mdx/get-started/sqlite/QueryTurso.mdx';
import QueryDatabaseUpdated from '@mdx/get-started/QueryDatabaseUpdated.mdx';
import RunFile from '@mdx/get-started/RunFile.mdx';
import ApplyChanges from '@mdx/get-started/sqlite/ApplyChanges.mdx';
import SetupEnv from '@mdx/get-started/SetupEnv.mdx';
import CreateTable from '@mdx/get-started/sqlite/CreateTable.mdx';
import ConnectLibsql from '@mdx/get-started/sqlite/ConnectLibsql.mdx';

<Breadcrumbs/>

# Get Started with Drizzle and SQLite Durable Objects

<Prerequisites>  
  - **dotenv** - package for managing environment variables - [read here](https://www.npmjs.com/package/dotenv)
  - **tsx** - package for running TypeScript files - [read here](https://tsx.hirok.io/)
  - **Cloudflare SQLite Durable Objects** - SQLite database embedded within a Durable Object - [read here](https://developers.cloudflare.com/durable-objects/api/sql-storage/)
  - **wrangler** - Cloudflare Developer Platform command-line interface - [read here](https://developers.cloudflare.com/workers/wrangler)
</Prerequisites>

<FileStructure />

#### Step 1 - Install required packages
<InstallPackages lib='wrangler'/>

#### Step 2 - Setup wrangler.toml

You would need to have a `wrangler.toml` file for D1 database and will look something like this:
```toml
#:schema node_modules/wrangler/config-schema.json
name = "sqlite-durable-objects"
main = "src/index.ts"
compatibility_date = "2024-11-12"
compatibility_flags = [ "nodejs_compat" ]

# Bind a Durable Object. Durable objects are a scale-to-zero compute primitive based on the actor model.
# Durable Objects can live for as long as needed. Use these when you need a long-running "server", such as in realtime apps.
# Docs: https://developers.cloudflare.com/workers/wrangler/configuration/#durable-objects
[[durable_objects.bindings]]
name = "MY_DURABLE_OBJECT"
class_name = "MyDurableObject"

# Durable Object migrations.
# Docs: https://developers.cloudflare.com/workers/wrangler/configuration/#migrations
[[migrations]]
tag = "v1"
new_sqlite_classes = ["MyDurableObject"]

# We need rules so we can import migrations in the next steps
[[rules]] 
type = "Text"
globs = ["**/*.sql"]
fallthrough = true
```

#### Step 3 - Connect Drizzle ORM to the database

```ts
import { drizzle, type DrizzleSqliteDODatabase } from 'drizzle-orm/durable-sqlite';
import { DurableObject } from 'cloudflare:workers'

export class MyDurableObject extends DurableObject {
	storage: DurableObjectStorage;
	db: DrizzleSqliteDODatabase;

	constructor(ctx: DurableObjectState, env: Env) {
		super(ctx, env);
		this.storage = ctx.storage;
		this.db = drizzle(this.storage, { logger: false });
	}
}
```

#### Step 4 - Generate wrangler types 

<Npx>
wrangler types
</Npx>

<Callout>
The output of this command will be a `worker-configuration.d.ts` file.
</Callout>

#### Step 5 - Create a table

<CreateTable/>

#### Step 6 - Setup Drizzle config file

**Drizzle config** - a configuration file that is used by [Drizzle Kit](/docs/kit-overview) and contains all the information about your database connection, migration folder and schema files.

Create a `drizzle.config.ts` file in the root of your project and add the following content:

```typescript copy filename="drizzle.config.ts"
import 'dotenv/config';
import { defineConfig } from 'drizzle-kit';

export default defineConfig({
  out: './drizzle',
  schema: './src/db/schema.ts',
  dialect: 'sqlite',
  driver: 'durable-sqlite',
});
```

#### Step 7 - Applying changes to the database

Generate migrations:
```bash copy
npx drizzle-kit generate
```

You can apply migrations only from Cloudflare Workers. 
To achieve this, let's define the migrate functionality in MyDurableObject:
```ts copy {4-5,17-19}
import { drizzle, type DrizzleSqliteDODatabase } from 'drizzle-orm/durable-sqlite';
import { DurableObject } from 'cloudflare:workers'
import { migrate } from 'drizzle-orm/durable-sqlite/migrator';
import migrations from '../drizzle/migrations';

export class MyDurableObject extends DurableObject {
	storage: DurableObjectStorage;
	db: DrizzleSqliteDODatabase;

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

#### Step 8 - Migrate and Query the database

```typescript copy
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 MyDurableObject 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 });

		// Make sure all migrations complete before accepting queries.
		// Otherwise you will need to run `this.migrate()` in any function
		// that accesses the Drizzle database `this.db`.
		ctx.blockConcurrencyWhile(async () => {
			await this._migrate();
		});
	}

	async insertAndList(user: typeof usersTable.$inferInsert) {
		await this.insert(user);
		return this.select();
	}

	async insert(user: typeof usersTable.$inferInsert) {
		await this.db.insert(usersTable).values(user);
	}

	async select() {
		return this.db.select().from(usersTable);
	}

	async _migrate() {
		migrate(this.db, migrations);
	}
}

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_OBJECT.idFromName('durable-object');
		const stub = env.MY_DURABLE_OBJECT.get(id);

		// Option A - Maximum performance.
		// Prefer to bundle all the database interaction within a single Durable Object call
		// for maximum performance, since database access is fast within a DO.
		const usersAll = await stub.insertAndList({
			name: 'John',
			age: 30,
			email: 'john@example.com',
		});
		console.log('New user created. Getting all users from the database: ', users);

		// Option B - Slow but maybe useful sometimes for debugging.
		// You can also directly call individual Drizzle queries if they are exposed
		// but keep in mind every query is a round-trip to the Durable Object instance.
		await stub.insert({
			name: 'John',
			age: 30,
			email: 'john@example.com',
		});
		console.log('New user created!');
	
		const users = await stub.select();
		console.log('Getting all users from the database: ', users);

		return Response.json(users);
	}
}
```

Source: https://orm.drizzle.team/docs/get-started/effect-postgresql-existing

import Tab from '@mdx/Tab.astro';
import Tabs from '@mdx/Tabs.astro';
import Npm from "@mdx/Npm.astro";
import Callout from '@mdx/Callout.astro';
import Steps from '@mdx/Steps.astro';
import AnchorCards from '@mdx/AnchorCards.astro';
import Breadcrumbs from '@mdx/Breadcrumbs.astro';
import CodeTabs from "@mdx/CodeTabs.astro";
import Prerequisites from "@mdx/Prerequisites.astro";
import IntrospectPostgreSQL from '@mdx/get-started/postgresql/IntrospectPostgreSQL.mdx';
import FileStructure from '@mdx/get-started/FileStructure.mdx';
import InstallPackages from '@mdx/get-started/InstallPackages.mdx';
import SetupConfig from '@mdx/get-started/SetupConfig.mdx';
import SetupEnv from '@mdx/get-started/SetupEnv.mdx';
import TransferCode from '@mdx/get-started/TransferCode.mdx';
import ApplyChanges from '@mdx/get-started/ApplyChanges.mdx';
import RunFile from '@mdx/get-started/RunFile.mdx';
import ConnectEffect from '@mdx/get-started/postgresql/ConnectEffect.mdx'
import UpdateSchema from '@mdx/get-started/postgresql/UpdateSchema.mdx';

<Breadcrumbs/>

# Get Started with Drizzle and Effect PostgreSQL in existing project

<Prerequisites>
  - **Effect** - Effect is a powerful TS library designed to help developers easily create complex, synchronous, and asynchronous programs. - [read more](https://effect.website/docs)
  - **dotenv** - package for managing environment variables - [read here](https://www.npmjs.com/package/dotenv)
  - **tsx** - package for running TypeScript files - [read here](https://tsx.hirok.io/)
  - **@effect/sql-pg** - A PostgreSQL toolkit for Effect - [read here](https://effect-ts.github.io/effect/docs/sql-pg)
</Prerequisites>

<FileStructure/>

#### Step 1 - Install required packages
<InstallPackages lib='effect @effect/sql-pg pg' devlib=' @types/pg'/>

#### Step 2 - Setup connection variables

<SetupEnv env_variable='DATABASE_URL' />

<Callout title='tips'>
If you don't have a PostgreSQL database yet and want to create one for testing, you can use our guide on how to set up PostgreSQL in Docker.

The PostgreSQL in Docker guide is available [here](/docs/guides/postgresql-local-setup). Go set it up, generate a database URL (explained in the guide), and come back for the next steps
</Callout>

#### Step 3 - Setup Drizzle config file

<SetupConfig dialect='postgresql' env_variable='DATABASE_URL'/>

#### Step 4 - Introspect your database

<IntrospectPostgreSQL/>

#### Step 5 - Transfer code to your actual schema file

<TransferCode/>

#### Step 6 - Connect Drizzle ORM to the database

<ConnectEffect/>

#### Step 7 - Query the database

```ts
import 'dotenv/config';
import * as PgDrizzle from 'drizzle-orm/effect-postgres';
import { PgClient } from '@effect/sql-pg';
import * as Effect from 'effect/Effect';
import * as Redacted from 'effect/Redacted';
import { types } from 'pg';
import { eq } from 'drizzle-orm';
import { usersTable } from './db/schema';

const PgClientLive = PgClient.layer({
  url: Redacted.make(process.env.DATABASE_URL!),
  types: {
    getTypeParser: (typeId, format) => {
      if ([1184, 1114, 1082, 1186, 1231, 1115, 1185, 1187, 1182].includes(typeId)) {
        return (val: any) => val;
      }
      return types.getTypeParser(typeId, format);
    },
  },
});

const program = Effect.gen(function*() {
  const db = yield* PgDrizzle.makeWithDefaults();

  const user: typeof usersTable.$inferInsert = {
    name: 'John',
    age: 30,
    email: 'john@example.com',
  };

  yield* db.insert(usersTable).values(user);
  console.log('New user created!')

  const users = yield* db.select().from(usersTable);
  console.log('Getting all users from the database: ', users)
  /*
  const users: {
    id: number;
    name: string;
    age: number;
    email: string;
  }[]
  */

  yield* db
    .update(usersTable)
    .set({
      age: 31,
    })
    .where(eq(usersTable.email, user.email));
  console.log('User info updated!')

  yield* db.delete(usersTable).where(eq(usersTable.email, user.email));
  console.log('User deleted!')
});

Effect.runPromise(program.pipe(Effect.provide(PgClientLive)));
```

#### Step 8 - Run index.ts file

<RunFile/>

#### Step 9 - Update your table schema (optional)

<UpdateSchema/>

#### Step 10 - Applying changes to the database (optional)

<ApplyChanges />

#### Step 11 - Query the database with a new field (optional)

```ts
import 'dotenv/config';
import * as PgDrizzle from 'drizzle-orm/effect-postgres';
import { PgClient } from '@effect/sql-pg';
import * as Effect from 'effect/Effect';
import * as Redacted from 'effect/Redacted';
import { types } from 'pg';
import { eq } from 'drizzle-orm';
import { usersTable } from './db/schema';

const PgClientLive = PgClient.layer({
  url: Redacted.make(process.env.DATABASE_URL!),
  types: {
    getTypeParser: (typeId, format) => {
      if ([1184, 1114, 1082, 1186, 1231, 1115, 1185, 1187, 1182].includes(typeId)) {
        return (val: any) => val;
      }
      return types.getTypeParser(typeId, format);
    },
  },
});

const program = Effect.gen(function*() {
  const db = yield* PgDrizzle.makeWithDefaults();

  const user: typeof usersTable.$inferInsert = {
    name: 'John',
    age: 30,
    email: 'john@example.com',
    phone: '123-456-7890',
  };

  yield* db.insert(usersTable).values(user);
  console.log('New user created!')

  const users = yield* db.select().from(usersTable);
  console.log('Getting all users from the database: ', users)
  /*
  const users: {
    id: number;
    name: string;
    age: number;
    email: string;
    phone: string | null;
  }[]
  */

  yield* db
    .update(usersTable)
    .set({
      age: 31,
    })
    .where(eq(usersTable.email, user.email));
  console.log('User info updated!')

  yield* db.delete(usersTable).where(eq(usersTable.email, user.email));
  console.log('User deleted!')
});

Effect.runPromise(program.pipe(Effect.provide(PgClientLive)));
```


Source: https://orm.drizzle.team/docs/get-started/effect-postgresql-new

import Tab from '@mdx/Tab.astro';
import Tabs from '@mdx/Tabs.astro';
import Npm from "@mdx/Npm.astro";
import Callout from '@mdx/Callout.astro';
import Steps from '@mdx/Steps.astro';
import AnchorCards from '@mdx/AnchorCards.astro';
import Breadcrumbs from '@mdx/Breadcrumbs.astro';
import Prerequisites from "@mdx/Prerequisites.astro";
import CodeTabs from "@mdx/CodeTabs.astro";
import FileStructure from '@mdx/get-started/FileStructure.mdx';
import InstallPackages from '@mdx/get-started/InstallPackages.mdx';
import ConnectEffect from '@mdx/get-started/postgresql/ConnectEffect.mdx'
import CreateTable from '@mdx/get-started/postgresql/CreateTable.mdx'
import SetupConfig from '@mdx/get-started/SetupConfig.mdx';
import ApplyChanges from '@mdx/get-started/ApplyChanges.mdx';
import RunFile from '@mdx/get-started/RunFile.mdx';
import QueryDatabase from '@mdx/get-started/QueryDatabase.mdx';
import SetupEnv from '@mdx/get-started/SetupEnv.mdx';

<Breadcrumbs/>

# Get Started with Drizzle and Effect PostgreSQL

<Prerequisites>
  - **Effect** - Effect is a powerful TS library designed to help developers easily create complex, synchronous, and asynchronous programs. - [read more](https://effect.website/docs)
  - **dotenv** - package for managing environment variables - [read here](https://www.npmjs.com/package/dotenv)
  - **tsx** - package for running TypeScript files - [read here](https://tsx.hirok.io/)
  - **@effect/sql-pg** - A PostgreSQL toolkit for Effect - [read here](https://effect-ts.github.io/effect/docs/sql-pg)
</Prerequisites>

Drizzle has native support for Effect PostgreSQL connections with the `@effect/sql-pg` driver.

<FileStructure/>

#### Step 1 - Install required packages
<InstallPackages lib='effect @effect/sql-pg pg' devlib=' @types/pg'/>

#### Step 2 - Setup connection variables

<SetupEnv env_variable='DATABASE_URL' />

<Callout title='tips'>
If you don't have a PostgreSQL database yet and want to create one for testing, you can use our guide on how to set up PostgreSQL in Docker.

The PostgreSQL in Docker guide is available [here](/docs/guides/postgresql-local-setup). Go set it up, generate a database URL (explained in the guide), and come back for the next steps
</Callout>

#### Step 3 - Connect Drizzle ORM to the database

<ConnectEffect />

#### Step 4 - Create a table

<CreateTable />

#### Step 5 - Setup Drizzle config file

<SetupConfig dialect='postgresql' env_variable='DATABASE_URL'/>

#### Step 6 - Applying changes to the database

<ApplyChanges />

#### Step 7 - Seed and Query the database

Let's **update** the `src/index.ts` file with queries to create, read, update, and delete users

```ts
import 'dotenv/config';
import * as PgDrizzle from 'drizzle-orm/effect-postgres';
import { PgClient } from '@effect/sql-pg';
import * as Effect from 'effect/Effect';
import * as Redacted from 'effect/Redacted';
import { types } from 'pg';
import { eq } from 'drizzle-orm';
import { usersTable } from './db/schema';

const PgClientLive = PgClient.layer({
  url: Redacted.make(process.env.DATABASE_URL!),
  types: {
    getTypeParser: (typeId, format) => {
      if ([1184, 1114, 1082, 1186, 1231, 1115, 1185, 1187, 1182].includes(typeId)) {
        return (val: any) => val;
      }
      return types.getTypeParser(typeId, format);
    },
  },
});

const program = Effect.gen(function*() {
  const db = yield* PgDrizzle.makeWithDefaults();

  const user: typeof usersTable.$inferInsert = {
    name: 'John',
    age: 30,
    email: 'john@example.com',
  };

  yield* db.insert(usersTable).values(user);
  console.log('New user created!')

  const users = yield* db.select().from(usersTable);
  console.log('Getting all users from the database: ', users)
  /*
  const users: {
    id: number;
    name: string;
    age: number;
    email: string;
  }[]
  */

  yield* db
    .update(usersTable)
    .set({
      age: 31,
    })
    .where(eq(usersTable.email, user.email));
  console.log('User info updated!')

  yield* db.delete(usersTable).where(eq(usersTable.email, user.email));
  console.log('User deleted!')
});

Effect.runPromise(program.pipe(Effect.provide(PgClientLive)));
```

#### Step 8 - Run index.ts file

<RunFile/>


Source: https://orm.drizzle.team/docs/get-started/expo-existing

import Breadcrumbs from '@mdx/Breadcrumbs.astro';

<Breadcrumbs/>

# Get Started with Drizzle and Expo in existing project

We don't have a proper guide for getting started with Expo in an existing project, and we believe that
all the information from this [getting started guide](/docs/get-started/expo-new) should be sufficient

Source: https://orm.drizzle.team/docs/get-started/expo-new

import Npm from '@mdx/Npm.astro';
import Npx from '@mdx/Npx.astro';
import Callout from '@mdx/Callout.astro';
import Prerequisites from "@mdx/Prerequisites.astro";
import CodeTabs from "@mdx/CodeTabs.astro";
import WhatsNextPostgres from "@mdx/WhatsNextPostgres.astro";
import Breadcrumbs from '@mdx/Breadcrumbs.astro';
import FileStructure from '@mdx/get-started/FileStructure.mdx';
import InstallPackages from '@mdx/get-started/InstallPackages.mdx';
import SetupConfig from '@mdx/get-started/SetupConfig.mdx';
import TransferCode from '@mdx/get-started/TransferCode.mdx';
import QueryDatabase from '@mdx/get-started/QueryDatabase.mdx';
import QueryDatabaseUpdated from '@mdx/get-started/QueryDatabaseUpdated.mdx';
import RunFile from '@mdx/get-started/RunFile.mdx';
import ApplyChanges from '@mdx/get-started/ApplyChanges.mdx';
import SetupEnv from '@mdx/get-started/SetupEnv.mdx';
import CreateTable from '@mdx/get-started/sqlite/CreateTable.mdx';
import ConnectLibsql from '@mdx/get-started/sqlite/ConnectLibsql.mdx';

<Breadcrumbs/>

# Get Started with Drizzle and Expo

<Prerequisites>  
  - **Expo SQLite** - A library that provides access to a database that can be queried through a SQLite API - [read here](https://docs.expo.dev/versions/latest/sdk/sqlite/)
</Prerequisites>


#### Step 1 - Setup a project from Expo Template
<Npx>
create expo-app --template blank-typescript
</Npx>

You can read more about this template [here](https://docs.expo.dev/more/create-expo/#create-a-new-project).

#### Basic file structure

After installing the template and adding the `db` folder, you'll find the following content: In the `db/schema.ts` file with drizzle table definitions. The `drizzle` folder contains SQL migration files and snapshots

```plaintext
📦 <project root>
 ├ 📂 assets
 ├ 📂 drizzle
 ├ 📂 db
 │  └ 📜 schema.ts
 ├ 📜 .gitignore
 ├ 📜 .npmrc
 ├ 📜 app.json
 ├ 📜 App.tsx
 ├ 📜 babel.config.ts
 ├ 📜 drizzle.config.ts
 ├ 📜 package.json
 └ 📜 tsconfig.json
```

#### Step 2 - Install expo-sqlite package
<Npx>
expo install expo-sqlite
</Npx>

#### Step 3 - Install required packages
<Npm>
    drizzle-orm@rc
    -D drizzle-kit@rc
</Npm>

#### Step 4 - Connect Drizzle ORM to the database

Create a `App.tsx` file in the root directory and initialize the connection:

```ts
import * as SQLite from 'expo-sqlite';
import { drizzle } from 'drizzle-orm/expo-sqlite';

const expo = SQLite.openDatabaseSync('db.db');

const db = drizzle(expo);
```

#### Step 4 - Create a table

Create a `schema.ts` file in the `db` directory and declare your table:

```typescript copy filename="src/db/schema.ts"
import { int, sqliteTable, text } from "drizzle-orm/sqlite-core";

export const usersTable = sqliteTable("users_table", {
  id: int().primaryKey({ autoIncrement: true }),
  name: text().notNull(),
  age: int().notNull(),
  email: text().notNull().unique(),
});
```

#### Step 5 - Setup Drizzle config file

**Drizzle config** - a configuration file that is used by [Drizzle Kit](/docs/kit-overview) and contains all the information about your database connection, migration folder and schema files.

Create a `drizzle.config.ts` file in the root of your project and add the following content:

```ts
import { defineConfig } from 'drizzle-kit';

export default defineConfig({
  dialect: 'sqlite',
  driver: 'expo',
  schema: './db/schema.ts',
  out: './drizzle',
});
```

#### Step 6 - Setup `metro` config

Create a file `metro.config.js` in root folder and add this code inside:

```js copy filename="metro.config.js"
const { getDefaultConfig } = require('expo/metro-config');
/** @type {import('expo/metro-config').MetroConfig} */
const config = getDefaultConfig(__dirname);
config.resolver.sourceExts.push('sql');
module.exports = config;
```

#### Step 7 - Update `babel` config
```js copy filename="babel.config.js"
module.exports = function(api) {
  api.cache(true);
  return {
    presets: ['babel-preset-expo'],
    plugins: [["inline-import", { "extensions": [".sql"] }]] // <-- add this
  };
};
```

#### Step 8 - Applying changes to the database

With Expo, you would need to generate migrations using the `drizzle-kit generate` command and then apply them at runtime using the `drizzle-orm` `migrate()` function

Generate migrations:
```bash copy
npx drizzle-kit generate
```

#### Step 9 - Apply migrations and query your db:

Let's **App.tsx** file with migrations and queries to create, read, update, and delete users

```ts copy
import { Text, View } from 'react-native';
import * as SQLite from 'expo-sqlite';
import { useEffect, useState } from 'react';
import { drizzle } from 'drizzle-orm/expo-sqlite';
import { usersTable } from './db/schema';
import { useMigrations } from 'drizzle-orm/expo-sqlite/migrator';
import migrations from './drizzle/migrations';

const expo = SQLite.openDatabaseSync('db.db');

const db = drizzle(expo);

export default function App() {
  const { success, error } = useMigrations(db, migrations);
  const [items, setItems] = useState<typeof usersTable.$inferSelect[] | null>(null);

  useEffect(() => {
    if (!success) return;

    (async () => {
      await db.delete(usersTable);

      await db.insert(usersTable).values([
        {
            name: 'John',
            age: 30,
            email: 'john@example.com',
        },
      ]);

      const users = await db.select().from(usersTable);
      setItems(users);
    })();
  }, [success]);

  if (error) {
    return (
      <View>
        <Text>Migration error: {error.message}</Text>
      </View>
    );
  }

  if (!success) {
    return (
      <View>
        <Text>Migration is in progress...</Text>
      </View>
    );
  }

  if (items === null || items.length === 0) {
    return (
      <View>
        <Text>Empty</Text>
      </View>
    );
  }

  return (
    <View
      style={{
        display: 'flex',
        flexDirection: 'column',
        alignItems: 'center',
        width: '100%',
        height: '100%',
        justifyContent: 'center',
      }}
    >
      {items.map((item) => (
        <Text key={item.id}>{item.email}</Text>
      ))}
    </View>
  );
}
```

#### Step 10 - Prebuild and run expo app

<CodeTabs items={['npm', 'yarn', 'pnpm', 'bun']}>
```bash copy
npx expo run:ios
```
```bash copy
yarn expo run:ios
```
```bash copy
pnpm expo run:ios
```
```bash copy
bun expo run:ios
```
</CodeTabs>


Source: https://orm.drizzle.team/docs/get-started/gel-existing

import Tab from '@mdx/Tab.astro';
import Tabs from '@mdx/Tabs.astro';
import Npm from "@mdx/Npm.astro";
import Npx from "@mdx/Npx.astro";
import Callout from '@mdx/Callout.astro';
import Steps from '@mdx/Steps.astro';
import AnchorCards from '@mdx/AnchorCards.astro';
import Breadcrumbs from '@mdx/Breadcrumbs.astro';
import Prerequisites from "@mdx/Prerequisites.astro";
import CodeTabs from "@mdx/CodeTabs.astro";
import FileStructure from '@mdx/get-started/FileStructure.mdx';
import InstallPackages from '@mdx/get-started/InstallPackages.mdx';
import ConnectPostgreSQL from '@mdx/get-started/postgresql/ConnectPostgreSQL.mdx'
import CreateTable from '@mdx/get-started/postgresql/CreateTable.mdx'
import SetupConfig from '@mdx/get-started/SetupConfig.mdx';
import ApplyChanges from '@mdx/get-started/ApplyChanges.mdx';
import RunFile from '@mdx/get-started/RunFile.mdx';
import QueryDatabase from '@mdx/get-started/QueryDatabase.mdx';
import SetupEnv from '@mdx/get-started/SetupEnv.mdx';

<Breadcrumbs/>

# Get Started with Drizzle and Gel in existing project

<Prerequisites>
  - **tsx** - package for running TypeScript files - [read here](https://tsx.hirok.io/)
  - **gel-js** - package for querying your Gel database - [read here](https://github.com/geldata/gel-js)
</Prerequisites>

Drizzle has native support for Gel connections with the `gel` client.

This is the basic file structure of the project. In the `src` directory, we have table definition in `index.ts`. In `drizzle` folder there are generated Gel to Drizzle schema

```plaintext
📦 <project root>
 ├ 📂 drizzle
 ├ 📂 dbschema
 │ ├ 📂 migrations
 │ ├ 📜 default.esdl
 │ └ 📜 scoping.esdl
 ├ 📂 src
 │ └ 📜 index.ts
 ├ 📜 drizzle.config.ts
 ├ 📜 edgedb.toml
 ├ 📜 package.json
 └ 📜 tsconfig.json
```

#### Step 1 - Install required packages
<Npm>
    drizzle-orm@rc gel
    -D drizzle-kit@rc tsx
</Npm>

#### Step 2 - Setup Drizzle config file

**Drizzle config** - a configuration file that is used by [Drizzle Kit](/docs/kit-overview) and contains all the information about your database connection, migration folder and schema files.

Create a `drizzle.config.ts` file in the root of your project and add the following content:

```typescript copy filename="drizzle.config.ts"
import { defineConfig } from 'drizzle-kit';

export default defineConfig({
  dialect: 'gel',
});
```

#### Step 3 - Pull Gel types to Drizzle schema

Pull your database schema:
<Npx>
drizzle-kit pull
</Npx>

Here is an example of the generated schema.ts file:

```typescript filename="drizzle/schema.ts"
import { gelTable, uniqueIndex, uuid, smallint, text } from "drizzle-orm/gel-core"
import { sql } from "drizzle-orm"

export const users = gelTable("users", {
	id: uuid().default(sql`uuid_generate_v4()`).primaryKey().notNull(),
	age: smallint(),
	email: text().notNull(),
	name: text(),
}, (table) => [
	uniqueIndex("a8c6061c-f37f-11ef-9249-0d78f6c1807b;schemaconstr").using("btree", table.id.asc().nullsLast().op("uuid_ops")),
]);
```

#### Step 4 - Connect Drizzle ORM to the database

Create a `index.ts` file in the `src` directory and initialize the connection:

```typescript copy filename="src/index.ts"
import { drizzle } from "drizzle-orm/gel";
import { createClient } from "gel";

const gelClient = createClient();
const db = drizzle({ client: gelClient });
```

#### Step 5 - Query the database

```typescript copy filename="src/index.ts"
import { eq } from "drizzle-orm";
import { drizzle } from "drizzle-orm/gel";
import { createClient } from "gel";
import { users } from "../drizzle/schema";

const gelClient = createClient();
const db = drizzle({ client: gelClient });

async function main() {
  const user: typeof users.$inferInsert = {
    name: "John",
    age: 30,
    email: "john@example.com",
  };

  await db.insert(users).values(user);
  console.log("New user created!");

  const usersResponse = await db.select().from(users);
  console.log("Getting all users from the database: ", usersResponse);
  /*
  const users: {
    id: number;
    name: string;
    age: number;
    email: string;
  }[]
  */

  await db
    .update(users)
    .set({
      age: 31,
    })
    .where(eq(users.email, user.email));
  console.log("User info updated!");

  await db.delete(users).where(eq(users.email, user.email));
  console.log("User deleted!");
}

main();
```

#### Step 6 - Run index.ts file

<RunFile/>


Source: https://orm.drizzle.team/docs/get-started/gel-new

import Tab from '@mdx/Tab.astro';
import Tabs from '@mdx/Tabs.astro';
import Npm from "@mdx/Npm.astro";
import Npx from "@mdx/Npx.astro";
import Callout from '@mdx/Callout.astro';
import Steps from '@mdx/Steps.astro';
import AnchorCards from '@mdx/AnchorCards.astro';
import Breadcrumbs from '@mdx/Breadcrumbs.astro';
import Prerequisites from "@mdx/Prerequisites.astro";
import CodeTabs from "@mdx/CodeTabs.astro";
import FileStructure from '@mdx/get-started/FileStructure.mdx';
import InstallPackages from '@mdx/get-started/InstallPackages.mdx';
import ConnectPostgreSQL from '@mdx/get-started/postgresql/ConnectPostgreSQL.mdx'
import CreateTable from '@mdx/get-started/postgresql/CreateTable.mdx'
import SetupConfig from '@mdx/get-started/SetupConfig.mdx';
import ApplyChanges from '@mdx/get-started/ApplyChanges.mdx';
import RunFile from '@mdx/get-started/RunFile.mdx';
import QueryDatabase from '@mdx/get-started/QueryDatabase.mdx';
import SetupEnv from '@mdx/get-started/SetupEnv.mdx';

<Breadcrumbs/>

# Get Started with Drizzle and Gel

<Prerequisites>
  - **tsx** - package for running TypeScript files - [read here](https://tsx.hirok.io/)
  - **gel-js** - package for querying your Gel database - [read here](https://github.com/geldata/gel-js)
</Prerequisites>

Drizzle has native support for Gel connections with the `gel` client.

This is the basic file structure of the project. In the `src` directory, we have table definition in `index.ts`. In `drizzle` folder there are generated Gel to Drizzle schema

```plaintext
📦 <project root>
 ├ 📂 drizzle
 ├ 📂 src
 │ └ 📜 index.ts
 ├ 📜 drizzle.config.ts
 ├ 📜 package.json
 └ 📜 tsconfig.json
```

#### Step 1 - Install and init **Gel** project

<Npx>
gel project init
</Npx>

#### Step 2 - Define basic Gel schema

In `dbschema/default.esdl` file add a basic Gel schema

```esdl
module default {
    type user {
        name: str;
        required email: str;
        age: int16;
    }
}
```

#### Step 3 - Push Gel schema to the database

Generate Gel migration file:
```bash
gel migration create
```

Apply Gel migrations to the database
```bash
gel migration apply
```

<Callout>
Now you should have this file structure

```plaintext
📦 <project root>
 ├ 📂 dbschema
 │ ├ 📂 migrations
 │ ├ 📜 default.esdl
 │ └ 📜 scoping.esdl
 ├ 📂 src
 │ └ 📜 index.ts
 ├ 📜 drizzle.config.ts
 ├ 📜 edgedb.toml
 ├ 📜 package.json
 └ 📜 tsconfig.json
```
</Callout>

#### Step 4 - Install required packages
<Npm>
    drizzle-orm@rc gel
    -D drizzle-kit@rc tsx
</Npm>

#### Step 5 - Setup Drizzle config file

**Drizzle config** - a configuration file that is used by [Drizzle Kit](/docs/kit-overview) and contains all the information about your database connection, migration folder and schema files.

Create a `drizzle.config.ts` file in the root of your project and add the following content:

```typescript copy filename="drizzle.config.ts"
import { defineConfig } from 'drizzle-kit';

export default defineConfig({
  dialect: 'gel',
});
```

#### Step 6 - Pull Gel types to Drizzle schema

Pull your database schema:
<Npx>
drizzle-kit pull
</Npx>

Here is an example of the generated schema.ts file:

```typescript filename="drizzle/schema.ts"
import { gelTable, uniqueIndex, uuid, smallint, text } from "drizzle-orm/gel-core"
import { sql } from "drizzle-orm"

export const users = gelTable("users", {
	id: uuid().default(sql`uuid_generate_v4()`).primaryKey().notNull(),
	age: smallint(),
	email: text().notNull(),
	name: text(),
}, (table) => [
	uniqueIndex("a8c6061c-f37f-11ef-9249-0d78f6c1807b;schemaconstr").using("btree", table.id.asc().nullsLast().op("uuid_ops")),
]);
```

#### Step 7 - Connect Drizzle ORM to the database

Create a `index.ts` file in the `src` directory and initialize the connection:

```typescript copy filename="src/index.ts"
import { drizzle } from "drizzle-orm/gel";
import { createClient } from "gel";

const gelClient = createClient();
const db = drizzle({ client: gelClient });
```

#### Step 8 - Query the database

```typescript copy filename="src/index.ts"
import { eq } from "drizzle-orm";
import { drizzle } from "drizzle-orm/gel";
import { createClient } from "gel";
import { users } from "../drizzle/schema";

const gelClient = createClient();
const db = drizzle({ client: gelClient });

async function main() {
  const user: typeof users.$inferInsert = {
    name: "John",
    age: 30,
    email: "john@example.com",
  };

  await db.insert(users).values(user);
  console.log("New user created!");

  const usersResponse = await db.select().from(users);
  console.log("Getting all users from the database: ", usersResponse);
  /*
  const users: {
    id: number;
    name: string;
    age: number;
    email: string;
  }[]
  */

  await db
    .update(users)
    .set({
      age: 31,
    })
    .where(eq(users.email, user.email));
  console.log("User info updated!");

  await db.delete(users).where(eq(users.email, user.email));
  console.log("User deleted!");
}

main();
```

#### Step 9 - Run index.ts file

<RunFile/>


Source: https://orm.drizzle.team/docs/get-started/mssql-existing

import Tab from '@mdx/Tab.astro';
import Tabs from '@mdx/Tabs.astro';
import Npm from "@mdx/Npm.astro";
import Callout from '@mdx/Callout.astro';
import Steps from '@mdx/Steps.astro';
import AnchorCards from '@mdx/AnchorCards.astro';
import Breadcrumbs from '@mdx/Breadcrumbs.astro';
import CodeTabs from "@mdx/CodeTabs.astro";
import Prerequisites from "@mdx/Prerequisites.astro";
import IntrospectMSSQL from '@mdx/get-started/mssql/IntrospectMSSQL.mdx';
import FileStructure from '@mdx/get-started/FileStructure.mdx';
import InstallPackages from '@mdx/get-started/InstallPackages.mdx';
import SetupConfig from '@mdx/get-started/mssql/SetupConfig.mdx';
import SetupEnv from '@mdx/get-started/SetupEnv.mdx';
import TransferCode from '@mdx/get-started/mssql/TransferCode.mdx';
import ApplyChanges from '@mdx/get-started/mssql/ApplyChanges.mdx';
import RunFile from '@mdx/get-started/RunFile.mdx';
import ConnectMSSQL from '@mdx/get-started/mssql/ConnectMSSQL.mdx'
import QueryDatabase from '@mdx/get-started/QueryDatabase.mdx';
import QueryDatabaseUpdated from '@mdx/get-started/QueryDatabaseUpdated.mdx';
import UpdateSchema from '@mdx/get-started/mssql/UpdateSchema.mdx';

<Breadcrumbs/>

# Get Started with Drizzle and MSSQL in existing project

<br/>

<Prerequisites>
  - **dotenv** - package for managing environment variables - [read here](https://www.npmjs.com/package/dotenv)
  - **tsx** - package for running TypeScript files - [read here](https://tsx.hirok.io/)
  - **node-mssql** - package for querying your MSSQL database - [read here](https://github.com/tediousjs/node-mssql)
</Prerequisites>

<FileStructure/>

#### Step 1 - Install **mssql** package
<Npm>
    drizzle-orm@rc mssql dotenv
    -D drizzle-kit@rc tsx
</Npm>

#### Step 2 - Setup connection variables

<SetupEnv env_variable='DATABASE_URL' />

#### Step 3 - Setup Drizzle config file

<SetupConfig dialect='mssql' env_variable='DATABASE_URL'/>

#### Step 4 - Introspect your database

<IntrospectMSSQL/>

#### Step 5 - Transfer code to your actual schema file

<TransferCode/>

#### Step 6 - Connect Drizzle ORM to the database

<ConnectMSSQL/>

#### Step 7 - Query the database

<QueryDatabase dialect='node-mssql' env_variable='DATABASE_URL'/>

#### Step 8 - Run index.ts file

<RunFile/>

#### Step 9 - Update your table schema (optional)

<UpdateSchema/>

#### Step 10 - Applying changes to the database (optional)

<ApplyChanges />

#### Step 11 - Query the database with a new field (optional)

<QueryDatabaseUpdated dialect='node-mssql' env_variable='DATABASE_URL' />


Source: https://orm.drizzle.team/docs/get-started/mssql-new

import Tab from '@mdx/Tab.astro';
import Tabs from '@mdx/Tabs.astro';
import Npm from "@mdx/Npm.astro";
import Callout from '@mdx/Callout.astro';
import Steps from '@mdx/Steps.astro';
import AnchorCards from '@mdx/AnchorCards.astro';
import Breadcrumbs from '@mdx/Breadcrumbs.astro';
import Prerequisites from "@mdx/Prerequisites.astro";
import CodeTabs from "@mdx/CodeTabs.astro";
import FileStructure from '@mdx/get-started/FileStructure.mdx';
import InstallPackages from '@mdx/get-started/InstallPackages.mdx';
import ConnectMSSQL from '@mdx/get-started/mssql/ConnectMSSQL.mdx'
import CreateTable from '@mdx/get-started/mssql/CreateTable.mdx'
import SetupConfig from '@mdx/get-started/mssql/SetupConfig.mdx';
import ApplyChanges from '@mdx/get-started/mssql/ApplyChanges.mdx';
import RunFile from '@mdx/get-started/RunFile.mdx';
import QueryDatabase from '@mdx/get-started/QueryDatabase.mdx';
import SetupEnv from '@mdx/get-started/SetupEnv.mdx';

<Breadcrumbs/>

# Get Started with Drizzle and MSSQL

<br/>

<Prerequisites>
  - **dotenv** - package for managing environment variables - [read here](https://www.npmjs.com/package/dotenv)
  - **tsx** - package for running TypeScript files - [read here](https://tsx.hirok.io/)
  - **node-mssql** - package for querying your MSSQL database - [read here](https://github.com/tediousjs/node-mssql)
</Prerequisites>

Drizzle has native support for PostgreSQL connections with the `node-mssql` driver.

<FileStructure/>

#### Step 1 - Install **mssql** package
<Npm>
    drizzle-orm@rc mssql dotenv
    -D drizzle-kit@rc tsx
</Npm>

#### Step 2 - Setup connection variables

<SetupEnv env_variable='DATABASE_URL' />

{/* <Callout title='tips'>
If you don't have a PostgreSQL database yet and want to create one for testing, you can use our guide on how to set up PostgreSQL in Docker.

The PostgreSQL in Docker guide is available [here](/docs/guides/postgresql-local-setup). Go set it up, generate a database URL (explained in the guide), and come back for the next steps
</Callout> */}

#### Step 3 - Connect Drizzle ORM to the database

<ConnectMSSQL/>

#### Step 4 - Create a table

<CreateTable />

#### Step 5 - Setup Drizzle config file

<SetupConfig dialect='mssql' env_variable='DATABASE_URL'/>

#### Step 6 - Applying changes to the database

<ApplyChanges />

#### Step 7 - Seed and Query the database

<QueryDatabase dialect='node-mssql' env_variable='DATABASE_URL'/>

#### Step 8 - Run index.ts file

<RunFile/>


Source: https://orm.drizzle.team/docs/get-started/mysql-existing

import Npm from '@mdx/Npm.astro';
import Callout from '@mdx/Callout.astro';
import Prerequisites from "@mdx/Prerequisites.astro";
import CodeTabs from "@mdx/CodeTabs.astro";
import WhatsNextPostgres from "@mdx/WhatsNextPostgres.astro";
import Breadcrumbs from '@mdx/Breadcrumbs.astro';
import FileStructure from '@mdx/get-started/FileStructure.mdx';
import InstallPackages from '@mdx/get-started/InstallPackages.mdx';
import SetupEnv from '@mdx/get-started/SetupEnv.mdx';
import ConnectMySQL from '@mdx/get-started/mysql/ConnectMySQL.mdx';
import CreateTable from '@mdx/get-started/mysql/CreateTable.mdx';
import UpdateSchema from '@mdx/get-started/mysql/UpdateSchema.mdx';
import IntrospectMySQL from '@mdx/get-started/mysql/IntrospectMySQL.mdx';
import QueryDatabase from '@mdx/get-started/QueryDatabase.mdx';
import QueryDatabaseUpdated from '@mdx/get-started/QueryDatabaseUpdated.mdx';
import ApplyChanges from '@mdx/get-started/mysql/ApplyChanges.mdx';
import RunFile from '@mdx/get-started/RunFile.mdx';
import SetupConfig from '@mdx/get-started/mysql/SetupConfig.mdx';
import TransferCode from '@mdx/get-started/TransferCode.mdx';

<Breadcrumbs/>

# Get Started with Drizzle and MySQL in existing project

<Prerequisites>  
  - **dotenv** - package for managing environment variables - [read here](https://www.npmjs.com/package/dotenv)
  - **tsx** - package for running TypeScript files - [read here](https://tsx.hirok.io/)
  - **mysql2** - package for querying your MySQL database - [read here](https://github.com/sidorares/node-mysql2)
</Prerequisites>

<FileStructure/>

#### Step 1 - Install the `mysql2` package

<InstallPackages lib='mysql2'/>

#### Step 2 - Setup connection variables

<SetupEnv env_variable='DATABASE_URL' />

#### Step 3 - Setup Drizzle config file

<SetupConfig dialect='mysql' env_variable='DATABASE_URL'/>

#### Step 4 - Introspect your database

<IntrospectMySQL/>

#### Step 5 - Transfer code to your actual schema file

<TransferCode/>

#### Step 6 - Connect Drizzle ORM to the database

<ConnectMySQL/>

#### Step 7 - Query the database

<QueryDatabase dialect='mysql2' env_variable='DATABASE_URL'/>

#### Step 8 - Run index.ts file

<RunFile/>

#### Step 9 - Update your table schema (optional)

<UpdateSchema/>

#### Step 10 - Applying changes to the database (optional)

<ApplyChanges/>

#### Step 11 - Query the database with a new field (optional)

<QueryDatabaseUpdated dialect='mysql2' env_variable='DATABASE_URL' />

Source: https://orm.drizzle.team/docs/get-started/mysql-new

import Npm from '@mdx/Npm.astro';
import Callout from '@mdx/Callout.astro';
import Prerequisites from "@mdx/Prerequisites.astro";
import CodeTabs from "@mdx/CodeTabs.astro";
import WhatsNextPostgres from "@mdx/WhatsNextPostgres.astro";
import Breadcrumbs from '@mdx/Breadcrumbs.astro';
import FileStructure from '@mdx/get-started/FileStructure.mdx';
import InstallPackages from '@mdx/get-started/InstallPackages.mdx';
import SetupEnv from '@mdx/get-started/SetupEnv.mdx';
import ConnectMySQL from '@mdx/get-started/mysql/ConnectMySQL.mdx';
import CreateTable from '@mdx/get-started/mysql/CreateTable.mdx';
import QueryDatabase from '@mdx/get-started/QueryDatabase.mdx';
import ApplyChanges from '@mdx/get-started/mysql/ApplyChanges.mdx';
import RunFile from '@mdx/get-started/RunFile.mdx';
import SetupConfig from '@mdx/get-started/mysql/SetupConfig.mdx';

<Breadcrumbs/>

# Get Started with Drizzle and MySQL

<Prerequisites>  
  - **dotenv** - package for managing environment variables - [read here](https://www.npmjs.com/package/dotenv)
  - **tsx** - package for running TypeScript files - [read here](https://tsx.hirok.io/)
  - **mysql2** - package for querying your MySQL database - [read here](https://github.com/sidorares/node-mysql2)
</Prerequisites>

To use Drizzle with a MySQL database, you should use the `mysql2` driver

According to the **[official website](https://github.com/sidorares/node-mysql2)**, 
`mysql2` is a MySQL client for Node.js with focus on performance.  

Drizzle ORM natively supports `mysql2` with `drizzle-orm/mysql2` package.

<FileStructure/>

#### Step 1 - Install **mysql2** package

<InstallPackages lib='mysql2'/>

#### Step 2 - Setup connection variables

<SetupEnv env_variable='DATABASE_URL' />

<Callout title='tips'>
If you don't have a MySQL database yet and want to create one for testing, you can use our guide on how to set up MySQL in Docker.

The MySQL in Docker guide is available [here](/docs/guides/mysql-local-setup). Go set it up, generate a database URL (explained in the guide), and come back for the next steps
</Callout>

#### Step 3 - Connect Drizzle ORM to the database

<ConnectMySQL/>

#### Step 4 - Create a table

<CreateTable/>

#### Step 5 - Setup Drizzle config file

<SetupConfig dialect='mysql' env_variable='DATABASE_URL'/>

#### Step 6 - Applying changes to the database

<ApplyChanges />

#### Step 7 - Seed and Query the database

<QueryDatabase dialect='mysql2' env_variable='DATABASE_URL'/>

#### Step 8 - Run index.ts file

<RunFile/>

Source: https://orm.drizzle.team/docs/get-started/neon-existing

import Tab from '@mdx/Tab.astro';
import Tabs from '@mdx/Tabs.astro';
import Npm from "@mdx/Npm.astro";
import Callout from '@mdx/Callout.astro';
import Steps from '@mdx/Steps.astro';
import AnchorCards from '@mdx/AnchorCards.astro';
import Breadcrumbs from '@mdx/Breadcrumbs.astro';
import CodeTabs from "@mdx/CodeTabs.astro";
import Prerequisites from "@mdx/Prerequisites.astro";
import IntrospectPostgreSQL from '@mdx/get-started/postgresql/IntrospectPostgreSQL.mdx';
import FileStructure from '@mdx/get-started/FileStructure.mdx';
import InstallPackages from '@mdx/get-started/InstallPackages.mdx';
import SetupConfig from '@mdx/get-started/SetupConfig.mdx';
import SetupEnv from '@mdx/get-started/SetupEnv.mdx';
import TransferCode from '@mdx/get-started/TransferCode.mdx';
import ApplyChanges from '@mdx/get-started/ApplyChanges.mdx';
import RunFile from '@mdx/get-started/RunFile.mdx';
import ConnectNeon from '@mdx/get-started/postgresql/ConnectNeon.mdx'
import QueryDatabase from '@mdx/get-started/QueryDatabase.mdx';
import QueryDatabaseUpdated from '@mdx/get-started/QueryDatabaseUpdated.mdx';
import UpdateSchema from '@mdx/get-started/postgresql/UpdateSchema.mdx';

<Breadcrumbs/>

# Get Started with Drizzle and Neon in existing project

<Prerequisites>
  - **dotenv** - package for managing environment variables - [read here](https://www.npmjs.com/package/dotenv)
  - **tsx** - package for running TypeScript files - [read here](https://tsx.hirok.io/)
  - **Neon** - serverless Postgres platform - [read here](https://neon.tech/docs/introduction)
</Prerequisites>

<FileStructure/>

#### Step 1 - Install **@neondatabase/serverless** package
<InstallPackages lib='@neondatabase/serverless'/>

#### Step 2 - Setup connection variables

<SetupEnv env_variable='DATABASE_URL' />

#### Step 3 - Setup Drizzle config file

<SetupConfig dialect='postgresql' env_variable='DATABASE_URL'/>

#### Step 4 - Introspect your database

<IntrospectPostgreSQL/>

#### Step 5 - Transfer code to your actual schema file

<TransferCode/>

#### Step 6 - Connect Drizzle ORM to the database

<ConnectNeon/>

#### Step 7 - Query the database

<QueryDatabase dialect='neon-http' env_variable='DATABASE_URL'/>

#### Step 8 - Run index.ts file

<RunFile/>

#### Step 9 - Update your table schema (optional)

<UpdateSchema/>

#### Step 10 - Applying changes to the database (optional)

<ApplyChanges />

#### Step 11 - Query the database with a new field (optional)

<QueryDatabaseUpdated dialect='neon-http' env_variable='DATABASE_URL' />

Source: https://orm.drizzle.team/docs/get-started/neon-new

import Tab from '@mdx/Tab.astro';
import Tabs from '@mdx/Tabs.astro';
import Npm from "@mdx/Npm.astro";
import Callout from '@mdx/Callout.astro';
import Steps from '@mdx/Steps.astro';
import AnchorCards from '@mdx/AnchorCards.astro';
import Breadcrumbs from '@mdx/Breadcrumbs.astro';
import Prerequisites from "@mdx/Prerequisites.astro";
import CodeTabs from "@mdx/CodeTabs.astro";
import FileStructure from '@mdx/get-started/FileStructure.mdx';
import InstallPackages from '@mdx/get-started/InstallPackages.mdx';
import ConnectNeon from '@mdx/get-started/postgresql/ConnectNeon.mdx'
import CreateTable from '@mdx/get-started/postgresql/CreateTable.mdx'
import SetupConfig from '@mdx/get-started/SetupConfig.mdx';
import ApplyChanges from '@mdx/get-started/ApplyChanges.mdx';
import RunFile from '@mdx/get-started/RunFile.mdx';
import QueryDatabase from '@mdx/get-started/QueryDatabase.mdx';
import SetupEnv from '@mdx/get-started/SetupEnv.mdx';

<Breadcrumbs/>

# Get Started with Drizzle and Neon

<Prerequisites>
  - **dotenv** - package for managing environment variables - [read here](https://www.npmjs.com/package/dotenv)
  - **tsx** - package for running TypeScript files - [read here](https://tsx.hirok.io/)
  - **Neon** - serverless Postgres platform - [read here](https://neon.tech/docs/introduction)
</Prerequisites>

Drizzle has native support for Neon connections with the `neon-http` and `neon-websockets` drivers. These use the **neon-serverless** driver under the hood.  
  
With the `neon-http` and `neon-websockets` drivers, you can access a Neon database from serverless environments over HTTP or WebSockets instead of TCP. Querying over HTTP is faster for single, non-interactive transactions.  
  
If you need session or interactive transaction support, or a fully compatible drop-in replacement for the `pg` driver, you can use the WebSocket-based `neon-serverless` driver. You can connect to a Neon database directly using [Postgres](/docs/get-started/postgresql-new)

<FileStructure/>

#### Step 1 - Install **@neondatabase/serverless** package
<InstallPackages lib='@neondatabase/serverless'/>

#### Step 2 - Setup connection variables

<SetupEnv env_variable='DATABASE_URL' />

#### Step 3 - Connect Drizzle ORM to the database

<ConnectNeon/>

#### Step 4 - Create a table

<CreateTable />

#### Step 5 - Setup Drizzle config file

<SetupConfig dialect='postgresql' env_variable='DATABASE_URL'/>

#### Step 6 - Applying changes to the database

<ApplyChanges />

#### Step 7 - Seed and Query the database

<QueryDatabase dialect='neon-http' env_variable='DATABASE_URL'/>

#### Step 8 - Run index.ts file

<RunFile/>

Source: https://orm.drizzle.team/docs/get-started/nile-existing

import Tab from '@mdx/Tab.astro';
import Tabs from '@mdx/Tabs.astro';
import Npm from "@mdx/Npm.astro";
import Callout from '@mdx/Callout.astro';
import Steps from '@mdx/Steps.astro';
import AnchorCards from '@mdx/AnchorCards.astro';
import Breadcrumbs from '@mdx/Breadcrumbs.astro';
import CodeTabs from "@mdx/CodeTabs.astro";
import Prerequisites from "@mdx/Prerequisites.astro";
import IntrospectPostgreSQL from '@mdx/get-started/postgresql/IntrospectPostgreSQL.mdx';
import FileStructure from '@mdx/get-started/FileStructure.mdx';
import InstallPackages from '@mdx/get-started/InstallPackages.mdx';
import SetupConfig from '@mdx/get-started/SetupConfig.mdx';
import SetupEnv from '@mdx/get-started/SetupEnv.mdx';
import TransferCode from '@mdx/get-started/TransferCode.mdx';
import ApplyChanges from '@mdx/get-started/ApplyChanges.mdx';
import RunFile from '@mdx/get-started/RunFile.mdx';
import ConnectNile from '@mdx/get-started/postgresql/ConnectNile.mdx'
import QueryNile from '@mdx/get-started/postgresql/QueryNile.mdx';
import QueryDatabaseUpdated from '@mdx/get-started/QueryDatabaseUpdated.mdx';
import UpdateSchema from '@mdx/get-started/postgresql/UpdateSchema.mdx';

<Breadcrumbs/>

# Get Started with Drizzle and Nile in existing project

<Prerequisites>
  - **dotenv** - package for managing environment variables - [read here](https://www.npmjs.com/package/dotenv)
  - **tsx** - package for running TypeScript files - [read here](https://tsx.hirok.io/)
  - **Nile** - PostgreSQL re-engineered for multi-tenant apps - [read here](https://thenile.dev/)
</Prerequisites>

<FileStructure/>

#### Step 1 - Install **postgres** package
<InstallPackages lib='pg' devlib=' @types/pg'/>

#### Step 2 - Setup connection variables

<SetupEnv env_variable='NILEDB_URL' />

#### Step 3 - Setup Drizzle config file

<SetupConfig dialect='postgresql' env_variable='NILEDB_URL'/>

#### Step 4 - Introspect your database

Drizzle Kit provides a CLI command to introspect your database and generate a schema file with migrations. The schema file contains all the information about your database tables, columns, relations, and indices.

For example, you have such table in your database:

```sql copy
CREATE TABLE IF NOT EXISTS "todos" (
  "id" uuid DEFAULT gen_random_uuid(),
  "tenant_id" uuid,
  "title" varchar(256),
  "estimate" varchar(256),
  "embedding" vector(3),
  "complete" boolean
);
```

Pull your database schema:

```bash copy
npx drizzle-kit pull
```

The result of introspection will be a `schema.ts` file, `meta` folder with snapshots of your database schema, sql file with the migration and `relations.ts` file for [relational queries](/docs/rqb).

<Callout title='built-in tables'>
Nile has several built-in tables that are part of every database. When you introspect a Nile database, the built-in tables will be included. 
For example, the `tenants` table that you see in the example below. This will allow you to easily create new tenants, list tenants and other operations.
</Callout>

Here is an example of the generated `schema.ts` file:

```typescript copy filename="src/db/schema.ts"
// table schema generated by introspection
import { pgTable, uuid, text, timestamp, varchar, vector, boolean } from "drizzle-orm/pg-core"
import { sql } from "drizzle-orm"

export const tenants = pgTable("tenants", {
	id: uuid().default(sql`public.uuid_generate_v7()`).primaryKey().notNull(),
	name: text(),
	created: timestamp({ mode: 'string' }).default(sql`LOCALTIMESTAMP`).notNull(),
	updated: timestamp({ mode: 'string' }).default(sql`LOCALTIMESTAMP`).notNull(),
	deleted: timestamp({ mode: 'string' }),
});

export const todos = pgTable("todos", {
	id: uuid().defaultRandom(),
	tenantId: uuid("tenant_id"),
	title: varchar({ length: 256 }),
	estimate: varchar({ length: 256 }),
	embedding: vector({ dimensions: 3 }),
	complete: boolean(),
});
```

Learn more about introspection in the [documentation](/docs/drizzle-kit-pull).

#### Step 5 - Transfer code to your actual schema file

<TransferCode/>

#### Step 6 - Connect Drizzle ORM to the database

<ConnectNile/>

#### Step 7 - Query the database

<QueryNile />

#### Step 8 - Run index.ts file

<RunFile/>

#### Step 9 - Update your table schema (optional)

If you want to update your table schema, you can do it in the `schema.ts` file. For example, let's add a new column `deadline` to the `todos` table`:

```typescript copy filename="src/db/schema.ts" {19}
import { pgTable, uuid, text, timestamp, varchar, vector, boolean } from "drizzle-orm/pg-core"
import { sql } from "drizzle-orm"

export const tenants = pgTable("tenants", {
	id: uuid().default(sql`public.uuid_generate_v7()`).primaryKey().notNull(),
	name: text(),
	created: timestamp({ mode: 'string' }).default(sql`LOCALTIMESTAMP`).notNull(),
	updated: timestamp({ mode: 'string' }).default(sql`LOCALTIMESTAMP`).notNull(),
	deleted: timestamp({ mode: 'string' }),
});

export const todos = pgTable("todos", {
	id: uuid().defaultRandom(),
	tenantId: uuid("tenant_id"),
	title: varchar({ length: 256 }),
	estimate: varchar({ length: 256 }),
	embedding: vector({ dimensions: 3 }),
	complete: boolean(),
  deadline: timestamp({ mode: 'string' })
});
```

#### Step 10 - Applying changes to the database (optional)

<ApplyChanges />

#### Step 11 - Query the database with a new field (optional)

If you run the `index.ts` file again, you'll be able to see the new field that you've just added. 
The field will be `null` since we did not populate deadlines when inserting todos previously.

<RunFile/>

Source: https://orm.drizzle.team/docs/get-started/nile-new

import Tab from '@mdx/Tab.astro';
import Tabs from '@mdx/Tabs.astro';
import Npm from "@mdx/Npm.astro";
import Callout from '@mdx/Callout.astro';
import Steps from '@mdx/Steps.astro';
import AnchorCards from '@mdx/AnchorCards.astro';
import Breadcrumbs from '@mdx/Breadcrumbs.astro';
import Prerequisites from "@mdx/Prerequisites.astro";
import CodeTabs from "@mdx/CodeTabs.astro";
import FileStructure from '@mdx/get-started/FileStructure.mdx';
import InstallPackages from '@mdx/get-started/InstallPackages.mdx';
import ConnectNile from '@mdx/get-started/postgresql/ConnectNile.mdx'
import CreateTable from '@mdx/get-started/postgresql/CreateTable.mdx'
import SetupConfig from '@mdx/get-started/SetupConfig.mdx';
import ApplyChanges from '@mdx/get-started/ApplyChanges.mdx';
import RunFile from '@mdx/get-started/RunFile.mdx';
import QueryNile from '@mdx/get-started/postgresql/QueryNile.mdx';
import SetupEnv from '@mdx/get-started/SetupEnv.mdx';


<Breadcrumbs/>

# Get Started with Drizzle and Nile

<Prerequisites>
  - **dotenv** - package for managing environment variables - [read here](https://www.npmjs.com/package/dotenv)
  - **tsx** - package for running TypeScript files - [read here](https://tsx.hirok.io/)
  - **Nile** - PostgreSQL re-engineered for multi-tenant apps - [read here](https://thenile.dev/)
</Prerequisites>

<FileStructure/>

#### Step 1 - Install **postgres** package
<InstallPackages lib='pg' devlib=' @types/pg'/>

#### Step 2 - Setup connection variables

<SetupEnv env_variable='NILEDB_URL' />

#### Step 3 - Connect Drizzle ORM to the database

<ConnectNile />

#### Step 4 - Create a table

Create a `schema.ts` file in the `src/db` directory and declare your tables. Since Nile is Postgres for multi-tenant apps, our schema includes a table for tenants and a todos table with a `tenant_id` column (we refer to those as tenant-aware tables):

```typescript copy filename="src/db/schema.ts"
import { pgTable, uuid, text, timestamp, varchar, vector, boolean } from "drizzle-orm/pg-core"
import { sql } from "drizzle-orm"

export const tenantsTable = pgTable("tenants", {
	id: uuid().default(sql`public.uuid_generate_v7()`).primaryKey().notNull(),
	name: text(),
	created: timestamp({ mode: 'string' }).default(sql`LOCALTIMESTAMP`).notNull(),
	updated: timestamp({ mode: 'string' }).default(sql`LOCALTIMESTAMP`).notNull(),
	deleted: timestamp({ mode: 'string' }),
});

export const todos = pgTable("todos", {
	id: uuid().defaultRandom(),
	tenantId: uuid("tenant_id"),
	title: varchar({ length: 256 }),
	estimate: varchar({ length: 256 }),
	embedding: vector({ dimensions: 3 }),
	complete: boolean(),
});
```

#### Step 5 - Setup Drizzle config file

<SetupConfig dialect='postgresql' env_variable='NILEDB_URL'/>

#### Step 6 - Applying changes to the database

<ApplyChanges dialect='postgresql'/>

#### Step 7 - Seed and Query the database

<QueryNile />

#### Step 8 - Run index.ts file

<RunFile/>

Source: https://orm.drizzle.team/docs/get-started/node-sqlite-existing

import Npm from '@mdx/Npm.astro';
import Npx from '@mdx/Npx.astro';
import Callout from '@mdx/Callout.astro';
import Prerequisites from "@mdx/Prerequisites.astro";
import CodeTabs from "@mdx/CodeTabs.astro";
import WhatsNextPostgres from "@mdx/WhatsNextPostgres.astro";
import Breadcrumbs from '@mdx/Breadcrumbs.astro';
import FileStructure from '@mdx/get-started/FileStructure.mdx';
import InstallPackages from '@mdx/get-started/InstallPackages.mdx';
import SetupConfig from '@mdx/get-started/SetupConfig.mdx';
import TransferCode from '@mdx/get-started/TransferCode.mdx';
import QueryDatabase from '@mdx/get-started/QueryDatabase.mdx';
import QueryDatabaseUpdated from '@mdx/get-started/QueryDatabaseUpdated.mdx';
import RunFile from '@mdx/get-started/RunFile.mdx';
import ApplyChanges from '@mdx/get-started/ApplyChanges.mdx';
import SetupEnv from '@mdx/get-started/SetupEnv.mdx';
import IntrospectSqlite from '@mdx/get-started/sqlite/IntrospectSqlite.mdx';
import ConnectNode from '@mdx/get-started/sqlite/ConnectNode.mdx';
import UpdateSchema from '@mdx/get-started/sqlite/UpdateSchema.mdx';

<Breadcrumbs/>

# Get Started with Drizzle and Node:SQLite in existing project

<Prerequisites>  
  - **node v22.5.0+** - JavaScript runtime - [read here](https://nodejs.org/)
  - **node:sqlite** - native implementation of a high-performance SQLite3 driver - [read here](https://nodejs.org/api/sqlite.html)
  - **dotenv** - package for managing environment variables - [read here](https://www.npmjs.com/package/dotenv)
  - **tsx** - package for running TypeScript files - [read here](https://tsx.is/)
</Prerequisites>

<FileStructure />

#### Step 1 - Install required packages

<Npm>
    drizzle-orm@rc dotenv
    -D drizzle-kit@rc tsx
</Npm>

#### Step 2 - Setup connection variables

<SetupEnv env_variable='DB_FILE_NAME' />

<Callout type='info' title='important'>
For example, if you have an SQLite database file in the root of your project, you can use this example:
```plaintext copy
DB_FILE_NAME=mydb.sqlite
```
</Callout>


#### Step 3 - Setup Drizzle config file

<SetupConfig dialect='sqlite' env_variable='DB_FILE_NAME'/>

#### Step 4 - Introspect your database

<IntrospectSqlite/>

#### Step 5 - Transfer code to your actual schema file

<TransferCode/>

#### Step 6 - Connect Drizzle ORM to the database

<ConnectNode/>

#### Step 7 - Query the database

<QueryDatabase dialect='node-sqlite' env_variable='DB_FILE_NAME' />

#### Step 8 - Run index.ts file

<RunFile/>

#### Step 9 - Update your table schema (optional)

<UpdateSchema/>

#### Step 9 - Applying changes to the database (optional)

<ApplyChanges/>

#### Step 10 - Query the database with a new field (optional)

<QueryDatabaseUpdated dialect='node-sqlite' env_variable='DB_FILE_NAME' />


Source: https://orm.drizzle.team/docs/get-started/node-sqlite-new

import Npm from '@mdx/Npm.astro';
import Npx from '@mdx/Npx.astro';
import Callout from '@mdx/Callout.astro';
import Prerequisites from "@mdx/Prerequisites.astro";
import CodeTabs from "@mdx/CodeTabs.astro";
import WhatsNextPostgres from "@mdx/WhatsNextPostgres.astro";
import Breadcrumbs from '@mdx/Breadcrumbs.astro';
import FileStructure from '@mdx/get-started/FileStructure.mdx';
import InstallPackages from '@mdx/get-started/InstallPackages.mdx';
import SetupConfig from '@mdx/get-started/SetupConfig.mdx';
import TransferCode from '@mdx/get-started/TransferCode.mdx';
import QueryDatabase from '@mdx/get-started/QueryDatabase.mdx';
import QueryDatabaseUpdated from '@mdx/get-started/QueryDatabaseUpdated.mdx';
import RunFile from '@mdx/get-started/RunFile.mdx';
import ApplyChanges from '@mdx/get-started/ApplyChanges.mdx';
import SetupEnv from '@mdx/get-started/SetupEnv.mdx';
import CreateTable from '@mdx/get-started/sqlite/CreateTable.mdx';
import ConnectNode from '@mdx/get-started/sqlite/ConnectNode.mdx';

<Breadcrumbs/>

# Get Started with Drizzle and Node:SQLite

<Prerequisites>
  - **node v22.5.0+** - JavaScript runtime - [read here](https://nodejs.org/)
  - **node:sqlite** - native implementation of a high-performance SQLite3 driver - [read here](https://nodejs.org/api/sqlite.html)
</Prerequisites>

<FileStructure />

#### Step 1 - Install required packages

<Npm>
    drizzle-orm@rc dotenv
    -D drizzle-kit@rc tsx
</Npm>

#### Step 2 - Setup connection variables

<SetupEnv env_variable='DB_FILE_NAME' />

<Callout type='info' title='important'>
For example, if you want to create an SQLite database file in the root of your project for testing purposes, you can use this example:
```plaintext copy
DB_FILE_NAME=mydb.sqlite
```
</Callout>

#### Step 3 - Connect Drizzle ORM to the database

<ConnectNode/>

#### Step 4 - Create a table

<CreateTable/>

#### Step 5 - Setup Drizzle config file

<SetupConfig dialect='sqlite' env_variable='DB_FILE_NAME'/>

#### Step 6 - Applying changes to the database

<ApplyChanges />

#### Step 7 - Seed and Query the database

<QueryDatabase dialect='node-sqlite' env_variable='DB_FILE_NAME'/>

#### Step 8 - Run index.ts file

<RunFile/>


Source: https://orm.drizzle.team/docs/get-started/op-sqlite-existing

import Breadcrumbs from '@mdx/Breadcrumbs.astro';

<Breadcrumbs/>

# Get Started with Drizzle and OP-SQLite in existing project

We don't have a proper guide for getting started with OP-SQLite in an existing project, and we believe that
all the information from this [getting started guide](/docs/get-started/op-sqlite-new) should be sufficient

Source: https://orm.drizzle.team/docs/get-started/op-sqlite-new

import Npm from '@mdx/Npm.astro';
import Npx from '@mdx/Npx.astro';
import Callout from '@mdx/Callout.astro';
import Prerequisites from "@mdx/Prerequisites.astro";
import CodeTabs from "@mdx/CodeTabs.astro";
import WhatsNextPostgres from "@mdx/WhatsNextPostgres.astro";
import Breadcrumbs from '@mdx/Breadcrumbs.astro';
import FileStructure from '@mdx/get-started/FileStructure.mdx';
import InstallPackages from '@mdx/get-started/InstallPackages.mdx';
import SetupConfig from '@mdx/get-started/SetupConfig.mdx';
import TransferCode from '@mdx/get-started/TransferCode.mdx';
import QueryDatabase from '@mdx/get-started/QueryDatabase.mdx';
import QueryDatabaseUpdated from '@mdx/get-started/QueryDatabaseUpdated.mdx';
import RunFile from '@mdx/get-started/RunFile.mdx';
import ApplyChanges from '@mdx/get-started/ApplyChanges.mdx';
import SetupEnv from '@mdx/get-started/SetupEnv.mdx';
import CreateTable from '@mdx/get-started/sqlite/CreateTable.mdx';
import ConnectLibsql from '@mdx/get-started/sqlite/ConnectLibsql.mdx';

<Breadcrumbs/>

# Get Started with Drizzle and OP-SQLite

<Prerequisites>  
  - **OP-SQLite** - SQLite library for react-native - [read here](https://github.com/OP-Engineering/op-sqlite)
</Prerequisites>


#### Step 1 - Setup a project from Expo Template
<Npx>
create expo-app --template blank-typescript
</Npx>

You can read more about this template [here](https://docs.expo.dev/more/create-expo/#create-a-new-project).

#### Basic file structure

After installing the template and adding the `db` folder, you'll find the following content: In the `db/schema.ts` file with drizzle table definitions. The `drizzle` folder contains SQL migration files and snapshots

```plaintext
📦 <project root>
 ├ 📂 assets
 ├ 📂 drizzle
 ├ 📂 db
 │  └ 📜 schema.ts
 ├ 📜 .gitignore
 ├ 📜 .npmrc
 ├ 📜 app.json
 ├ 📜 App.tsx
 ├ 📜 babel.config.ts
 ├ 📜 drizzle.config.ts
 ├ 📜 package.json
 └ 📜 tsconfig.json
```

#### Step 2 - Install required packages
<Npm>
    drizzle-orm@rc @op-engineering/op-sqlite
    -D drizzle-kit@rc
</Npm>

#### Step 3 - Connect Drizzle ORM to the database

Create a `App.tsx` file in the root directory and initialize the connection:

```ts
import { open } from '@op-engineering/op-sqlite';
import { drizzle } from 'drizzle-orm/op-sqlite';

const opsqliteDb = open({
  name: 'db',
});

const db = drizzle(opsqliteDb);
```

#### Step 4 - Create a table

Create a `schema.ts` file in the `db` directory and declare your table:

```typescript copy filename="src/db/schema.ts"
import { int, sqliteTable, text } from "drizzle-orm/sqlite-core";

export const usersTable = sqliteTable("users_table", {
  id: int().primaryKey({ autoIncrement: true }),
  name: text().notNull(),
  age: int().notNull(),
  email: text().notNull().unique(),
});
```

#### Step 5 - Setup Drizzle config file

**Drizzle config** - a configuration file that is used by [Drizzle Kit](/docs/kit-overview) and contains all the information about your database connection, migration folder and schema files.

Create a `drizzle.config.ts` file in the root of your project and add the following content:

```ts
import { defineConfig } from 'drizzle-kit';

export default defineConfig({
  dialect: 'sqlite',
  driver: 'expo',
  schema: './db/schema.ts',
  out: './drizzle',
});
```

#### Step 6 - Setup `metro` config

Create a file `metro.config.js` in root folder and add this code inside:

```js copy filename="metro.config.js"
const { getDefaultConfig } = require('expo/metro-config');
/** @type {import('expo/metro-config').MetroConfig} */
const config = getDefaultConfig(__dirname);
config.resolver.sourceExts.push('sql');
module.exports = config;
```

#### Step 7 - Update `babel` config
```js copy filename="babel.config.js"
module.exports = function(api) {
  api.cache(true);
  return {
    presets: ['babel-preset-expo'],
    plugins: [["inline-import", { "extensions": [".sql"] }]] // <-- add this
  };
};
```

#### Step 8 - Applying changes to the database

With Expo, you would need to generate migrations using the `drizzle-kit generate` command and then apply them at runtime using the `drizzle-orm` `migrate()` function

Generate migrations:
```bash copy
npx drizzle-kit generate
```

#### Step 9 - Apply migrations and query your db:

Let's **App.tsx** file with migrations and queries to create, read, update, and delete users

```ts copy
import { Text, View } from 'react-native';
import { open } from '@op-engineering/op-sqlite';
import { useEffect, useState } from 'react';
import { drizzle } from 'drizzle-orm/op-sqlite';
import { usersTable } from './db/schema';
import { useMigrations } from 'drizzle-orm/op-sqlite/migrator';
import migrations from './drizzle/migrations';

const opsqliteDb = open({
  name: 'db',
});

const db = drizzle(opsqliteDb);

export default function App() {
  const { success, error } = useMigrations(db, migrations);
  const [items, setItems] = useState<typeof usersTable.$inferSelect[] | null>(null);

  useEffect(() => {
    if (!success) return;

    (async () => {
      await db.delete(usersTable);

      await db.insert(usersTable).values([
        {
            name: 'John',
            age: 30,
            email: 'john@example.com',
        },
      ]);

      const users = await db.select().from(usersTable);
      setItems(users);
    })();
  }, [success]);

  if (error) {
    return (
      <View>
        <Text>Migration error: {error.message}</Text>
      </View>
    );
  }

  if (!success) {
    return (
      <View>
        <Text>Migration is in progress...</Text>
      </View>
    );
  }

  if (items === null || items.length === 0) {
    return (
      <View>
        <Text>Empty</Text>
      </View>
    );
  }

  return (
    <View
      style={{
        display: 'flex',
        flexDirection: 'column',
        alignItems: 'center',
        width: '100%',
        height: '100%',
        justifyContent: 'center',
      }}
    >
      {items.map((item) => (
        <Text key={item.id}>{item.email}</Text>
      ))}
    </View>
  );
}
```

#### Step 10 - Prebuild and run expo app

<CodeTabs items={['npm', 'yarn', 'pnpm', 'bun']}>
```bash copy
npx expo run:ios
```
```bash copy
yarn expo run:ios
```
```bash copy
pnpm expo run:ios
```
```bash copy
bun expo run:ios
```
</CodeTabs>


Source: https://orm.drizzle.team/docs/get-started/pglite-existing

import Tab from '@mdx/Tab.astro';
import Tabs from '@mdx/Tabs.astro';
import Npm from "@mdx/Npm.astro";
import Callout from '@mdx/Callout.astro';
import Steps from '@mdx/Steps.astro';
import AnchorCards from '@mdx/AnchorCards.astro';
import Breadcrumbs from '@mdx/Breadcrumbs.astro';
import CodeTabs from "@mdx/CodeTabs.astro";
import Prerequisites from "@mdx/Prerequisites.astro";
import IntrospectPostgreSQL from '@mdx/get-started/postgresql/IntrospectPostgreSQL.mdx';
import FileStructure from '@mdx/get-started/FileStructure.mdx';
import InstallPackages from '@mdx/get-started/InstallPackages.mdx';
import SetupConfig from '@mdx/get-started/SetupConfig.mdx';
import SetupEnv from '@mdx/get-started/SetupEnv.mdx';
import TransferCode from '@mdx/get-started/TransferCode.mdx';
import ApplyChanges from '@mdx/get-started/ApplyChanges.mdx';
import RunFile from '@mdx/get-started/RunFile.mdx';
import ConnectPgLite from '@mdx/get-started/postgresql/ConnectPgLite.mdx'
import QueryDatabase from '@mdx/get-started/QueryDatabase.mdx';
import QueryDatabaseUpdated from '@mdx/get-started/QueryDatabaseUpdated.mdx';
import UpdateSchema from '@mdx/get-started/postgresql/UpdateSchema.mdx';

<Breadcrumbs/>

# Get Started with Drizzle and PGLite in existing project

<Prerequisites>
  - **dotenv** - package for managing environment variables - [read here](https://www.npmjs.com/package/dotenv)
  - **tsx** - package for running TypeScript files - [read here](https://tsx.hirok.io/)
  - **ElectricSQL** - [website](https://electric-sql.com/)
  - **pglite driver** - [docs](https://pglite.dev/) & [GitHub](https://github.com/electric-sql/pglite)
</Prerequisites>

<FileStructure/>

#### Step 1 - Install all needed packages
<InstallPackages lib='@electric-sql/pglite' />

#### Step 2 - Setup connection variables

<SetupEnv env_variable='DATABASE_URL' />

#### Step 3 - Setup Drizzle config file

<SetupConfig dialect='postgresql' env_variable='DATABASE_URL'/>

#### Step 4 - Introspect your database

<IntrospectPostgreSQL/>

#### Step 5 - Transfer code to your actual schema file

<TransferCode/>

#### Step 6 - Connect Drizzle ORM to the database

<ConnectPgLite/>

#### Step 7 - Query the database

<QueryDatabase dialect='pglite' env_variable='DATABASE_URL'/>

#### Step 8 - Run index.ts file

<RunFile/>

#### Step 9 - Update your table schema (optional)

<UpdateSchema/>

#### Step 10 - Applying changes to the database (optional)

<ApplyChanges />

#### Step 11 - Query the database with a new field (optional)

<QueryDatabaseUpdated dialect='pglite' env_variable='DATABASE_URL' />

Source: https://orm.drizzle.team/docs/get-started/pglite-new

import Tab from '@mdx/Tab.astro';
import Tabs from '@mdx/Tabs.astro';
import Npm from "@mdx/Npm.astro";
import Callout from '@mdx/Callout.astro';
import Steps from '@mdx/Steps.astro';
import AnchorCards from '@mdx/AnchorCards.astro';
import Breadcrumbs from '@mdx/Breadcrumbs.astro';
import Prerequisites from "@mdx/Prerequisites.astro";
import CodeTabs from "@mdx/CodeTabs.astro";
import FileStructure from '@mdx/get-started/FileStructure.mdx';
import InstallPackages from '@mdx/get-started/InstallPackages.mdx';
import ConnectPgLite from '@mdx/get-started/postgresql/ConnectPgLite.mdx'
import CreateTable from '@mdx/get-started/postgresql/CreateTable.mdx'
import SetupConfig from '@mdx/get-started/SetupConfig.mdx';
import ApplyChanges from '@mdx/get-started/ApplyChanges.mdx';
import RunFile from '@mdx/get-started/RunFile.mdx';
import QueryDatabase from '@mdx/get-started/QueryDatabase.mdx';
import SetupEnv from '@mdx/get-started/SetupEnv.mdx';

<Breadcrumbs/>

# Get Started with Drizzle and PGlite

<Prerequisites>
  - **dotenv** - package for managing environment variables - [read here](https://www.npmjs.com/package/dotenv)
  - **tsx** - package for running TypeScript files - [read here](https://tsx.hirok.io/)
  - **ElectricSQL** - [website](https://electric-sql.com/)
  - **pglite driver** - [docs](https://pglite.dev/) & [GitHub](https://github.com/electric-sql/pglite)
</Prerequisites>

<FileStructure/>

#### Step 1 - Install all needed packages
<InstallPackages lib='@electric-sql/pglite' />

#### Step 2 - Setup connection variables

<SetupEnv env_variable='DATABASE_URL' />

#### Step 3 - Connect Drizzle ORM to the database

<ConnectPgLite/>

#### Step 4 - Create a table

<CreateTable />

#### Step 5 - Setup Drizzle config file

<SetupConfig dialect='postgresql' env_variable='DATABASE_URL'/>

#### Step 6 - Applying changes to the database

<ApplyChanges />

#### Step 7 - Seed and Query the database

<QueryDatabase dialect='pglite' env_variable='DATABASE_URL'/>

#### Step 8 - Run index.ts file

<RunFile/>

Source: https://orm.drizzle.team/docs/get-started/planetscale-existing

import Npm from '@mdx/Npm.astro';
import Callout from '@mdx/Callout.astro';
import Prerequisites from "@mdx/Prerequisites.astro";
import CodeTabs from "@mdx/CodeTabs.astro";
import WhatsNextPostgres from "@mdx/WhatsNextPostgres.astro";
import Breadcrumbs from '@mdx/Breadcrumbs.astro';
import FileStructure from '@mdx/get-started/FileStructure.mdx';
import InstallPackages from '@mdx/get-started/InstallPackages.mdx';
import SetupEnv from '@mdx/get-started/SetupEnv.mdx';
import ConnectPlanetScale from '@mdx/get-started/mysql/ConnectPlanetScale.mdx';
import CreateTable from '@mdx/get-started/mysql/CreateTable.mdx';
import UpdateSchema from '@mdx/get-started/mysql/UpdateSchema.mdx';
import IntrospectMySQL from '@mdx/get-started/mysql/IntrospectMySQL.mdx';
import QueryPlanetScale from '@mdx/get-started/mysql/QueryPlanetScale.mdx';
import ApplyChanges from '@mdx/get-started/mysql/ApplyChanges.mdx';
import RunFile from '@mdx/get-started/RunFile.mdx';
import SetupConfig from '@mdx/get-started/mysql/SetupConfig.mdx';
import TransferCode from '@mdx/get-started/TransferCode.mdx';

<Breadcrumbs/>

# Get Started with Drizzle and PlanetScale in existing project

<Prerequisites>  
  - **dotenv** - package for managing environment variables - [read here](https://www.npmjs.com/package/dotenv)
  - **tsx** - package for running TypeScript files - [read here](https://tsx.hirok.io)
  - **PlanetScale** - MySQL database platform - [read here](https://planetscale.com)
  - **database-js** - PlanetScale serverless driver - [read here](https://github.com/planetscale/database-js)
</Prerequisites>

<Callout title='PlanetScale also offers Postgres' type='info'>
Looking for PostgreSQL? Check out our [PlanetScale Postgres guide](/docs/get-started/planetscale-postgres-existing)
</Callout>

<Callout title='important' type='warning'>
For this tutorial, we will use the `database-js` driver to make **HTTP** calls to the PlanetScale database. If you need to
connect to PlanetScale through TCP, you can refer to our [MySQL Get Started](/docs/get-started/mysql-new) page
</Callout>

<FileStructure/>

#### Step 1 - Install **@planetscale/database** package

<InstallPackages lib='@planetscale/database'/>

#### Step 2 - Setup connection variables

<SetupEnv env_variable='DATABASE_URL' />

#### Step 3 - Setup Drizzle config file

<SetupConfig dialect='mysql' env_variable='DATABASE_URL'/>

#### Step 4 - Introspect your database

<IntrospectMySQL/>

#### Step 5 - Transfer code to your actual schema file

<TransferCode/>

#### Step 6 - Connect Drizzle ORM to the database

<ConnectPlanetScale/>

#### Step 7 - Query the database

<QueryPlanetScale />

#### Step 8 - Run index.ts file

<RunFile/>

#### Step 9 - Update your table schema (optional)

<UpdateSchema/>

#### Step 10 - Applying changes to the database (optional)

<ApplyChanges/>

#### Step 11 - Query the database with a new field (optional)

```typescript copy filename="src/index.ts"
import 'dotenv/config';
import { eq } from 'drizzle-orm';
import { drizzle } from 'drizzle-orm/planetscale-serverless';
import { usersTable } from './db/schema';

async function main() {
  const db = drizzle({ connection: {
      host: process.env.DATABASE_HOST!,
      username: process.env.DATABASE_USERNAME!,
      password: process.env.DATABASE_PASSWORD!,
    }});

  const user: typeof usersTable.$inferInsert = {
    name: 'John',
    age: 30,
    email: 'john@example.com',
    phone: '123-456-7890',
  };

  await db.insert(usersTable).values(user);
  console.log('New user created!')

  const users = await db.select().from(usersTable);
  console.log('Getting all users from the database: ', users)
  /*
  const users: {
    id: number;
    name: string;
    age: number;
    email: string;
    phone: string | null;
  }[]
  */

  await db
    .update(usersTable)
    .set({
      age: 31,
    })
    .where(eq(usersTable.email, user.email));
  console.log('User info updated!')

  await db.delete(usersTable).where(eq(usersTable.email, user.email));
  console.log('User deleted!')
}

main();
```

Source: https://orm.drizzle.team/docs/get-started/planetscale-new

import Npm from '@mdx/Npm.astro';
import Callout from '@mdx/Callout.astro';
import Prerequisites from "@mdx/Prerequisites.astro";
import CodeTabs from "@mdx/CodeTabs.astro";
import WhatsNextPostgres from "@mdx/WhatsNextPostgres.astro";
import Breadcrumbs from '@mdx/Breadcrumbs.astro';
import FileStructure from '@mdx/get-started/FileStructure.mdx';
import InstallPackages from '@mdx/get-started/InstallPackages.mdx';
import SetupEnv from '@mdx/get-started/SetupEnv.mdx';
import ConnectPlanetScale from '@mdx/get-started/mysql/ConnectPlanetScale.mdx';
import CreateTable from '@mdx/get-started/mysql/CreateTable.mdx';
import QueryPlanetScale from '@mdx/get-started/mysql/QueryPlanetScale.mdx';
import ApplyChanges from '@mdx/get-started/mysql/ApplyChanges.mdx';
import RunFile from '@mdx/get-started/RunFile.mdx';
import SetupConfig from '@mdx/get-started/mysql/SetupConfig.mdx';

<Breadcrumbs/>

# Get Started with Drizzle and PlanetScale

<Prerequisites>  
  - **dotenv** - package for managing environment variables - [read here](https://www.npmjs.com/package/dotenv)
  - **tsx** - package for running TypeScript files - [read here](https://tsx.hirok.io)
  - **PlanetScale** - MySQL database platform - [read here](https://planetscale.com)
  - **database-js** - PlanetScale serverless driver - [read here](https://github.com/planetscale/database-js)
</Prerequisites>

<Callout title='PlanetScale also offers Postgres' type='info'>
Looking for PostgreSQL? Check out our [PlanetScale Postgres guide](/docs/get-started/planetscale-postgres-new)
</Callout>

<Callout title='important' type='warning'>
For this tutorial, we will use the `database-js` driver to make **HTTP** calls to the PlanetScale database. If you need to
connect to PlanetScale through TCP, you can refer to our [MySQL Get Started](/docs/get-started/mysql-new) page
</Callout>

<FileStructure/>

#### Step 1 - Install **@planetscale/database** package

<InstallPackages lib='@planetscale/database'/>

#### Step 2 - Setup connection variables

Create a `.env` file in the root of your project and add your database connection variable:

```plaintext copy
DATABASE_HOST=
DATABASE_USERNAME=
DATABASE_PASSWORD=
```

<Callout title='tips'>
To get all the necessary environment variables to connect through the `database-js` driver, you can check the [PlanetScale docs](https://planetscale.com/docs/tutorials/planetscale-serverless-driver-node-example#use-the-sample-repository)
</Callout>

#### Step 3 - Connect Drizzle ORM to the database

<ConnectPlanetScale/>

#### Step 4 - Create a table

<CreateTable/>

#### Step 5 - Setup Drizzle config file

<SetupConfig dialect='mysql' env_variable='DATABASE_URL'/>

#### Step 6 - Applying changes to the database

<ApplyChanges />

#### Step 7 - Seed and Query the database

<QueryPlanetScale />

#### Step 8 - Run index.ts file

<RunFile/>

Source: https://orm.drizzle.team/docs/get-started/planetscale-postgres-existing

import Tab from '@mdx/Tab.astro';
import Tabs from '@mdx/Tabs.astro';
import Npm from "@mdx/Npm.astro";
import Callout from '@mdx/Callout.astro';
import Steps from '@mdx/Steps.astro';
import AnchorCards from '@mdx/AnchorCards.astro';
import Breadcrumbs from '@mdx/Breadcrumbs.astro';
import CodeTabs from "@mdx/CodeTabs.astro";
import Prerequisites from "@mdx/Prerequisites.astro";
import IntrospectPostgreSQL from '@mdx/get-started/postgresql/IntrospectPostgreSQL.mdx';
import FileStructure from '@mdx/get-started/FileStructure.mdx';
import InstallPackages from '@mdx/get-started/InstallPackages.mdx';
import SetupConfig from '@mdx/get-started/SetupConfig.mdx';
import SetupEnv from '@mdx/get-started/SetupEnv.mdx';
import TransferCode from '@mdx/get-started/TransferCode.mdx';
import ApplyChanges from '@mdx/get-started/ApplyChanges.mdx';
import RunFile from '@mdx/get-started/RunFile.mdx';
import ConnectPlanetScalePostgres from '@mdx/get-started/postgresql/ConnectPlanetScalePostgres.mdx'
import QueryDatabase from '@mdx/get-started/QueryDatabase.mdx';
import QueryDatabaseUpdated from '@mdx/get-started/QueryDatabaseUpdated.mdx';
import UpdateSchema from '@mdx/get-started/postgresql/UpdateSchema.mdx';

<Breadcrumbs/>

# Get Started with Drizzle and PlanetScale Postgres in existing project

<Prerequisites>
  - **dotenv** - package for managing environment variables - [read here](https://www.npmjs.com/package/dotenv)
  - **tsx** - package for running TypeScript files - [read here](https://tsx.hirok.io/)
  - **PlanetScale Postgres** - PostgreSQL database platform - [read here](https://planetscale.com/docs/postgres)
  - **node-postgres** - package for querying your PostgreSQL database - [read here](https://node-postgres.com/)
</Prerequisites>

<Callout title='PlanetScale also offers MySQL' type='info'>
Looking for MySQL? Check out our [PlanetScale MySQL guide](/docs/get-started/planetscale-existing)
</Callout>

PlanetScale offers both MySQL (Vitess) and PostgreSQL databases. This guide covers connecting to PlanetScale Postgres using the standard `node-postgres` driver.

For detailed instructions on creating a PlanetScale Postgres database and obtaining credentials, see the [PlanetScale Postgres documentation](https://planetscale.com/docs/postgres/tutorials/planetscale-postgres-drizzle).

<FileStructure/>

#### Step 1 - Install **node-postgres** package
<InstallPackages lib='pg' devlib=' @types/pg'/>

#### Step 2 - Setup connection variables

Create a `.env` file in the root of your project and add your database connection variable:

```plaintext copy
DATABASE_URL=postgresql://{username}:{password}@{host}:{port}/postgres?sslmode=verify-full
```

<Callout title='tips'>
You can obtain your connection credentials from the PlanetScale dashboard by navigating to your database, clicking **"Connect"**, and creating a **"Default role"**. See the [PlanetScale connection guide](https://planetscale.com/docs/postgres/tutorials/planetscale-postgres-drizzle#create-credentials-and-connect) for detailed steps.
</Callout>

#### Step 3 - Setup Drizzle config file

<SetupConfig dialect='postgresql' env_variable='DATABASE_URL'/>

#### Step 4 - Introspect your database

<IntrospectPostgreSQL/>

#### Step 5 - Transfer code to your actual schema file

<TransferCode/>

#### Step 6 - Connect Drizzle ORM to the database

<ConnectPlanetScalePostgres/>

#### Step 7 - Query the database

<QueryDatabase dialect='node-postgres' env_variable='DATABASE_URL'/>

#### Step 8 - Run index.ts file

<RunFile/>

#### Step 9 - Update your table schema (optional)

<UpdateSchema/>

#### Step 10 - Applying changes to the database (optional)

<ApplyChanges />

#### Step 11 - Query the database with a new field (optional)

<QueryDatabaseUpdated dialect='node-postgres' env_variable='DATABASE_URL' />


Source: https://orm.drizzle.team/docs/get-started/planetscale-postgres-new

import Tab from '@mdx/Tab.astro';
import Tabs from '@mdx/Tabs.astro';
import Npm from "@mdx/Npm.astro";
import Callout from '@mdx/Callout.astro';
import Steps from '@mdx/Steps.astro';
import AnchorCards from '@mdx/AnchorCards.astro';
import Breadcrumbs from '@mdx/Breadcrumbs.astro';
import Prerequisites from "@mdx/Prerequisites.astro";
import CodeTabs from "@mdx/CodeTabs.astro";
import FileStructure from '@mdx/get-started/FileStructure.mdx';
import InstallPackages from '@mdx/get-started/InstallPackages.mdx';
import ConnectPlanetScalePostgres from '@mdx/get-started/postgresql/ConnectPlanetScalePostgres.mdx'
import CreateTable from '@mdx/get-started/postgresql/CreateTable.mdx'
import SetupConfig from '@mdx/get-started/SetupConfig.mdx';
import ApplyChanges from '@mdx/get-started/ApplyChanges.mdx';
import RunFile from '@mdx/get-started/RunFile.mdx';
import QueryDatabase from '@mdx/get-started/QueryDatabase.mdx';
import SetupEnv from '@mdx/get-started/SetupEnv.mdx';

<Breadcrumbs/>

# Get Started with Drizzle and PlanetScale Postgres

<Prerequisites>
  - **dotenv** - package for managing environment variables - [read here](https://www.npmjs.com/package/dotenv)
  - **tsx** - package for running TypeScript files - [read here](https://tsx.hirok.io/)
  - **PlanetScale Postgres** - PostgreSQL database platform - [read here](https://planetscale.com/docs/postgres)
  - **node-postgres** - package for querying your PostgreSQL database - [read here](https://node-postgres.com/)
</Prerequisites>

<Callout title='PlanetScale also offers MySQL' type='info'>
Looking for MySQL? Check out our [PlanetScale MySQL guide](/docs/get-started/planetscale-new)
</Callout>

PlanetScale offers both MySQL (Vitess) and PostgreSQL databases. This guide covers connecting to PlanetScale Postgres using the standard `node-postgres` driver.

For detailed instructions on creating a PlanetScale Postgres database and obtaining credentials, see the [PlanetScale Postgres documentation](https://planetscale.com/docs/postgres/tutorials/planetscale-postgres-drizzle).

<FileStructure/>

#### Step 1 - Install **node-postgres** package
<InstallPackages lib='pg' devlib=' @types/pg'/>

#### Step 2 - Setup connection variables

Create a `.env` file in the root of your project and add your database connection variable:

```plaintext copy
DATABASE_URL=postgresql://{username}:{password}@{host}:{port}/postgres?sslmode=verify-full
```

<Callout title='tips'>
You can obtain your connection credentials from the PlanetScale dashboard by navigating to your database, clicking **"Connect"**, and creating a **"Default role"**. See the [PlanetScale connection guide](https://planetscale.com/docs/postgres/tutorials/planetscale-postgres-drizzle#create-credentials-and-connect) for detailed steps.
</Callout>

#### Step 3 - Connect Drizzle ORM to the database

<ConnectPlanetScalePostgres/>

#### Step 4 - Create a table

<CreateTable />

#### Step 5 - Setup Drizzle config file

<SetupConfig dialect='postgresql' env_variable='DATABASE_URL'/>

#### Step 6 - Applying changes to the database

<ApplyChanges />

#### Step 7 - Seed and Query the database

<QueryDatabase dialect='node-postgres' env_variable='DATABASE_URL'/>

#### Step 8 - Run index.ts file

<RunFile/>


Source: https://orm.drizzle.team/docs/get-started/postgresql-existing

import Tab from '@mdx/Tab.astro';
import Tabs from '@mdx/Tabs.astro';
import Npm from "@mdx/Npm.astro";
import Callout from '@mdx/Callout.astro';
import Steps from '@mdx/Steps.astro';
import AnchorCards from '@mdx/AnchorCards.astro';
import Breadcrumbs from '@mdx/Breadcrumbs.astro';
import CodeTabs from "@mdx/CodeTabs.astro";
import Prerequisites from "@mdx/Prerequisites.astro";
import IntrospectPostgreSQL from '@mdx/get-started/postgresql/IntrospectPostgreSQL.mdx';
import FileStructure from '@mdx/get-started/FileStructure.mdx';
import InstallPackages from '@mdx/get-started/InstallPackages.mdx';
import SetupConfig from '@mdx/get-started/SetupConfig.mdx';
import SetupEnv from '@mdx/get-started/SetupEnv.mdx';
import TransferCode from '@mdx/get-started/TransferCode.mdx';
import ApplyChanges from '@mdx/get-started/ApplyChanges.mdx';
import RunFile from '@mdx/get-started/RunFile.mdx';
import ConnectPostgreSQL from '@mdx/get-started/postgresql/ConnectPostgreSQL.mdx'
import QueryDatabase from '@mdx/get-started/QueryDatabase.mdx';
import QueryDatabaseUpdated from '@mdx/get-started/QueryDatabaseUpdated.mdx';
import UpdateSchema from '@mdx/get-started/postgresql/UpdateSchema.mdx';

<Breadcrumbs/>

# Get Started with Drizzle and PostgreSQL in existing project

<Prerequisites>
  - **dotenv** - package for managing environment variables - [read here](https://www.npmjs.com/package/dotenv)
  - **tsx** - package for running TypeScript files - [read here](https://tsx.hirok.io/)
  - **node-postgres** - package for querying your PostgreSQL database - [read here](https://node-postgres.com/)
</Prerequisites>

<FileStructure/>

#### Step 1 - Install **node-postgres** package
<InstallPackages lib='pg' devlib=' @types/pg'/>

#### Step 2 - Setup connection variables

<SetupEnv env_variable='DATABASE_URL' />

<Callout title='tips'>
If you don't have a PostgreSQL database yet and want to create one for testing, you can use our guide on how to set up PostgreSQL in Docker.

The PostgreSQL in Docker guide is available [here](/docs/guides/postgresql-local-setup). Go set it up, generate a database URL (explained in the guide), and come back for the next steps
</Callout>

#### Step 3 - Setup Drizzle config file

<SetupConfig dialect='postgresql' env_variable='DATABASE_URL'/>

#### Step 4 - Introspect your database

<IntrospectPostgreSQL/>

#### Step 5 - Transfer code to your actual schema file

<TransferCode/>

#### Step 6 - Connect Drizzle ORM to the database

<ConnectPostgreSQL/>

#### Step 7 - Query the database

<QueryDatabase dialect='node-postgres' env_variable='DATABASE_URL'/>

#### Step 8 - Run index.ts file

<RunFile/>

#### Step 9 - Update your table schema (optional)

<UpdateSchema/>

#### Step 10 - Applying changes to the database (optional)

<ApplyChanges />

#### Step 11 - Query the database with a new field (optional)

<QueryDatabaseUpdated dialect='node-postgres' env_variable='DATABASE_URL' />

Source: https://orm.drizzle.team/docs/get-started/postgresql-new

import Tab from '@mdx/Tab.astro';
import Tabs from '@mdx/Tabs.astro';
import Npm from "@mdx/Npm.astro";
import Callout from '@mdx/Callout.astro';
import Steps from '@mdx/Steps.astro';
import AnchorCards from '@mdx/AnchorCards.astro';
import Breadcrumbs from '@mdx/Breadcrumbs.astro';
import Prerequisites from "@mdx/Prerequisites.astro";
import CodeTabs from "@mdx/CodeTabs.astro";
import FileStructure from '@mdx/get-started/FileStructure.mdx';
import InstallPackages from '@mdx/get-started/InstallPackages.mdx';
import ConnectPostgreSQL from '@mdx/get-started/postgresql/ConnectPostgreSQL.mdx'
import CreateTable from '@mdx/get-started/postgresql/CreateTable.mdx'
import SetupConfig from '@mdx/get-started/SetupConfig.mdx';
import ApplyChanges from '@mdx/get-started/ApplyChanges.mdx';
import RunFile from '@mdx/get-started/RunFile.mdx';
import QueryDatabase from '@mdx/get-started/QueryDatabase.mdx';
import SetupEnv from '@mdx/get-started/SetupEnv.mdx';

<Breadcrumbs/>

# Get Started with Drizzle and PostgreSQL

<Prerequisites>
  - **dotenv** - package for managing environment variables - [read here](https://www.npmjs.com/package/dotenv)
  - **tsx** - package for running TypeScript files - [read here](https://tsx.hirok.io/)
  - **node-postgres** - package for querying your PostgreSQL database - [read here](https://node-postgres.com/)
</Prerequisites>

Drizzle has native support for PostgreSQL connections with the `node-postgres` and `postgres.js` drivers.

We will use `node-postgres` for this get started example. But if you want to find more ways to connect to postgresql check
our [PostgreSQL Connection](/docs/get-started-postgresql) page 

<FileStructure/>

#### Step 1 - Install **node-postgres** package
<InstallPackages lib='pg' devlib=' @types/pg'/>

#### Step 2 - Setup connection variables

<SetupEnv env_variable='DATABASE_URL' />

<Callout title='tips'>
If you don't have a PostgreSQL database yet and want to create one for testing, you can use our guide on how to set up PostgreSQL in Docker.

The PostgreSQL in Docker guide is available [here](/docs/guides/postgresql-local-setup). Go set it up, generate a database URL (explained in the guide), and come back for the next steps
</Callout>

#### Step 3 - Connect Drizzle ORM to the database

<ConnectPostgreSQL/>

#### Step 4 - Create a table

<CreateTable />

#### Step 5 - Setup Drizzle config file

<SetupConfig dialect='postgresql' env_variable='DATABASE_URL'/>

#### Step 6 - Applying changes to the database

<ApplyChanges />

#### Step 7 - Seed and Query the database

<QueryDatabase dialect='node-postgres' env_variable='DATABASE_URL'/>

#### Step 8 - Run index.ts file

<RunFile/>

Source: https://orm.drizzle.team/docs/get-started/singlestore-existing

import Npm from '@mdx/Npm.astro';
import Callout from '@mdx/Callout.astro';
import Prerequisites from "@mdx/Prerequisites.astro";
import CodeTabs from "@mdx/CodeTabs.astro";
import WhatsNextPostgres from "@mdx/WhatsNextPostgres.astro";
import Breadcrumbs from '@mdx/Breadcrumbs.astro';
import FileStructure from '@mdx/get-started/FileStructure.mdx';
import InstallPackages from '@mdx/get-started/InstallPackages.mdx';
import SetupEnv from '@mdx/get-started/SetupEnv.mdx';
import ConnectSingleStore from '@mdx/get-started/singlestore/ConnectSingleStore.mdx';
import UpdateSchema from '@mdx/get-started/singlestore/UpdateSchema.mdx';
import IntrospectSingleStore from '@mdx/get-started/singlestore/IntrospectSingleStore.mdx';
import QueryDatabase from '@mdx/get-started/QueryDatabase.mdx';
import QueryDatabaseUpdated from '@mdx/get-started/QueryDatabaseUpdated.mdx';
import ApplyChanges from '@mdx/get-started/singlestore/ApplyChanges.mdx';
import RunFile from '@mdx/get-started/RunFile.mdx';
import SetupConfig from '@mdx/get-started/singlestore/SetupConfig.mdx';
import TransferCode from '@mdx/get-started/TransferCode.mdx';

<Breadcrumbs/>

# Get Started with Drizzle and SingleStore in existing project

<Prerequisites>  
  - **dotenv** - package for managing environment variables - [read here](https://www.npmjs.com/package/dotenv)
  - **tsx** - package for running TypeScript files - [read here](https://tsx.hirok.io/)
  - **mysql2** - package for querying your SingleStore database - [read here](https://github.com/sidorares/node-mysql2)
</Prerequisites>

<FileStructure/>

#### Step 1 - Install the `mysql2` package

<InstallPackages lib='mysql2'/>

#### Step 2 - Setup connection variables

<SetupEnv env_variable='DATABASE_URL' />

#### Step 3 - Setup Drizzle config file

<SetupConfig dialect='singlestore' env_variable='DATABASE_URL'/>

#### Step 4 - Introspect your database

<IntrospectSingleStore/>

#### Step 5 - Transfer code to your actual schema file

<TransferCode/>

#### Step 6 - Connect Drizzle ORM to the database

<ConnectSingleStore/>

#### Step 7 - Query the database

<QueryDatabase dialect='singlestore' env_variable='DATABASE_URL'/>

#### Step 8 - Run index.ts file

<RunFile/>

#### Step 9 - Update your table schema (optional)

<UpdateSchema/>

#### Step 10 - Applying changes to the database (optional)

<ApplyChanges/>

#### Step 11 - Query the database with a new field (optional)

<QueryDatabaseUpdated dialect='singlestore' env_variable='DATABASE_URL' />

Source: https://orm.drizzle.team/docs/get-started/singlestore-new

import Npm from '@mdx/Npm.astro';
import Callout from '@mdx/Callout.astro';
import Prerequisites from "@mdx/Prerequisites.astro";
import CodeTabs from "@mdx/CodeTabs.astro";
import WhatsNextPostgres from "@mdx/WhatsNextPostgres.astro";
import Breadcrumbs from '@mdx/Breadcrumbs.astro';
import FileStructure from '@mdx/get-started/FileStructure.mdx';
import InstallPackages from '@mdx/get-started/InstallPackages.mdx';
import SetupEnv from '@mdx/get-started/SetupEnv.mdx';
import ConnectSingleStore from '@mdx/get-started/singlestore/ConnectSingleStore.mdx';
import CreateSingleStoreTable from '@mdx/get-started/singlestore/CreateSingleStoreTable.mdx';
import QueryDatabase from '@mdx/get-started/QueryDatabase.mdx';
import ApplyChanges from '@mdx/get-started/singlestore/ApplyChanges.mdx';
import RunFile from '@mdx/get-started/RunFile.mdx';
import SetupConfig from '@mdx/get-started/singlestore/SetupConfig.mdx';

<Breadcrumbs/>

# Get Started with Drizzle and SingleStore

<Prerequisites>  
  - **dotenv** - package for managing environment variables - [read here](https://www.npmjs.com/package/dotenv)
  - **tsx** - package for running TypeScript files - [read here](https://tsx.hirok.io/)
  - **mysql2** - package for querying your MySQL database - [read here](https://github.com/sidorares/node-mysql2)
</Prerequisites>

To use Drizzle with a SingleStore database, you should use the `singlestore` driver

According to the **[official website](https://github.com/sidorares/node-mysql2)**, 
`mysql2` is a MySQL client for Node.js with focus on performance.  

Drizzle ORM natively supports `mysql2` with `drizzle-orm/singlestore` package for SingleStore database.

<FileStructure/>

#### Step 1 - Install **mysql2** package

<InstallPackages lib='mysql2'/>

#### Step 2 - Setup connection variables

<SetupEnv env_variable='DATABASE_URL' />

#### Step 3 - Connect Drizzle ORM to the database

<ConnectSingleStore/>

#### Step 4 - Create a table

<CreateSingleStoreTable/>

#### Step 5 - Setup Drizzle config file

<SetupConfig dialect='singlestore' env_variable='DATABASE_URL'/>

#### Step 6 - Applying changes to the database

<ApplyChanges />

#### Step 7 - Seed and Query the database

<QueryDatabase dialect='singlestore' env_variable='DATABASE_URL'/>

#### Step 8 - Run index.ts file

<RunFile/>

Source: https://orm.drizzle.team/docs/get-started/sqlite-cloud-existing

import Tab from '@mdx/Tab.astro';
import Tabs from '@mdx/Tabs.astro';
import Npm from "@mdx/Npm.astro";
import Callout from '@mdx/Callout.astro';
import Steps from '@mdx/Steps.astro';
import AnchorCards from '@mdx/AnchorCards.astro';
import Breadcrumbs from '@mdx/Breadcrumbs.astro';
import CodeTabs from "@mdx/CodeTabs.astro";
import Prerequisites from "@mdx/Prerequisites.astro";
import IntrospectSQLite from '@mdx/get-started/sqlite/IntrospectSqlite.mdx';
import FileStructure from '@mdx/get-started/FileStructure.mdx';
import InstallPackages from '@mdx/get-started/InstallPackages.mdx';
import SetupConfig from '@mdx/get-started/sqlite/SetupConfig.mdx';
import SetupEnv from '@mdx/get-started/SetupEnv.mdx';
import TransferCode from '@mdx/get-started/TransferCode.mdx';
import ApplyChanges from '@mdx/get-started/sqlite/ApplyChanges.mdx';
import RunFile from '@mdx/get-started/RunFile.mdx';
import ConnectSQLiteCloud from '@mdx/get-started/sqlite/ConnectSQLiteCloud.mdx';
import QueryDatabase from '@mdx/get-started/QueryDatabase.mdx';
import QueryDatabaseUpdated from '@mdx/get-started/QueryDatabaseUpdated.mdx';
import UpdateSchema from '@mdx/get-started/sqlite/UpdateSchema.mdx';

<Breadcrumbs/>

# Get Started with Drizzle and SQLite Cloud in existing project

<Prerequisites>
  - **dotenv** - package for managing environment variables - [read here](https://www.npmjs.com/package/dotenv)
  - **tsx** - package for running TypeScript files - [read here](https://tsx.hirok.io/)
  - **SQLite Cloud database** - [read here](https://docs.sqlitecloud.io/docs/overview)
  - **SQLite Cloud driver** - [read here](https://docs.sqlitecloud.io/docs/sdk-js-introduction) & [GitHub](https://github.com/sqlitecloud/sqlitecloud-js)
</Prerequisites>

<FileStructure/>

#### Step 1 - Install required package
<Npm>
    drizzle-orm@rc @sqlitecloud/drivers dotenv
    -D drizzle-kit@rc tsx
</Npm>

#### Step 2 - Setup connection variables

<SetupEnv env_variable='SQLITE_CLOUD_CONNECTION_STRING' />

#### Step 3 - Setup Drizzle config file

<SetupConfig dialect='sqlite' env_variable='SQLITE_CLOUD_CONNECTION_STRING'/>

#### Step 4 - Introspect your database

<IntrospectSQLite/>

#### Step 5 - Transfer code to your actual schema file

<TransferCode/>

#### Step 6 - Connect Drizzle ORM to the database

<ConnectSQLiteCloud/>

#### Step 7 - Query the database

```typescript copy filename="src/index.ts"
import 'dotenv/config';
import { eq } from 'drizzle-orm';
import { drizzle } from 'drizzle-orm/sqlite-cloud';
import { usersTable } from './db/schema';

async function main() {
  const db = drizzle();

  const user: typeof usersTable.$inferInsert = {
    name: 'John',
    age: 30,
    email: 'john@example.com',
  };

  await db.insert(usersTable).values(user);
  console.log('New user created!')

  const users = await db.select().from(usersTable);
  console.log('Getting all users from the database: ', users)
  /*
  const users: {
    id: number;
    name: string;
    age: number;
    email: string;
  }[]
  */

  await db
    .update(usersTable)
    .set({
      age: 31,
    })
    .where(eq(usersTable.email, user.email));
  console.log('User info updated!')

  await db.delete(usersTable).where(eq(usersTable.email, user.email));
  console.log('User deleted!')
}

main();
```

#### Step 8 - Run index.ts file

<RunFile/>

#### Step 9 - Update your table schema (optional)

<UpdateSchema/>

#### Step 10 - Applying changes to the database (optional)

<ApplyChanges />

#### Step 11 - Query the database with a new field (optional)

```typescript copy filename="src/index.ts"
import 'dotenv/config';
import { eq } from 'drizzle-orm';
import { drizzle } from 'drizzle-orm/sqlite-cloud';
import { usersTable } from './db/schema';

async function main() {
  const db = drizzle();

  const user: typeof usersTable.$inferInsert = {
    name: 'John',
    age: 30,
    email: 'john@example.com',
    phone: '123-456-7890',
  };

  await db.insert(usersTable).values(user);
  console.log('New user created!')

  const users = await db.select().from(usersTable);
  console.log('Getting all users from the database: ', users)
  /*
  const users: {
    id: number;
    name: string;
    age: number;
    email: string;
    phone: string | null;
  }[]
  */

  await db
    .update(usersTable)
    .set({
      age: 31,
    })
    .where(eq(usersTable.email, user.email));
  console.log('User info updated!')

  await db.delete(usersTable).where(eq(usersTable.email, user.email));
  console.log('User deleted!')
}

main();
```


Source: https://orm.drizzle.team/docs/get-started/sqlite-cloud-new

import Tab from '@mdx/Tab.astro';
import Tabs from '@mdx/Tabs.astro';
import Npm from "@mdx/Npm.astro";
import Callout from '@mdx/Callout.astro';
import Steps from '@mdx/Steps.astro';
import AnchorCards from '@mdx/AnchorCards.astro';
import Breadcrumbs from '@mdx/Breadcrumbs.astro';
import Prerequisites from "@mdx/Prerequisites.astro";
import CodeTabs from "@mdx/CodeTabs.astro";
import FileStructure from '@mdx/get-started/FileStructure.mdx';
import InstallPackages from '@mdx/get-started/InstallPackages.mdx';
import ConnectSQLiteCloud from '@mdx/get-started/sqlite/ConnectSQLiteCloud.mdx'
import CreateTable from '@mdx/get-started/sqlite/CreateTable.mdx'
import SetupConfig from '@mdx/get-started/sqlite/SetupConfig.mdx';
import ApplyChanges from '@mdx/get-started/sqlite/ApplyChanges.mdx';
import RunFile from '@mdx/get-started/RunFile.mdx';
import QueryDatabase from '@mdx/get-started/QueryDatabase.mdx';
import SetupEnv from '@mdx/get-started/SetupEnv.mdx';

<Breadcrumbs/>

# Get Started with Drizzle and SQLite Cloud

<Prerequisites>
  - **dotenv** - package for managing environment variables - [read here](https://www.npmjs.com/package/dotenv)
  - **tsx** - package for running TypeScript files - [read here](https://tsx.hirok.io/)
  - **SQLite Cloud database** - [read here](https://docs.sqlitecloud.io/docs/overview)
  - **SQLite Cloud driver** - [read here](https://docs.sqlitecloud.io/docs/sdk-js-introduction) & [GitHub](https://github.com/sqlitecloud/sqlitecloud-js)
</Prerequisites>

<FileStructure/>

#### Step 1 - Install required package
<Npm>
    drizzle-orm@rc @sqlitecloud/drivers dotenv
    -D drizzle-kit@rc tsx
</Npm>

#### Step 2 - Setup connection variables

<SetupEnv env_variable='SQLITE_CLOUD_CONNECTION_STRING' />

#### Step 3 - Connect Drizzle ORM to the database

<ConnectSQLiteCloud/>

#### Step 4 - Create a table

<CreateTable />

#### Step 5 - Setup Drizzle config file

<SetupConfig dialect='sqlite' env_variable='SQLITE_CLOUD_CONNECTION_STRING'/>

#### Step 6 - Applying changes to the database

<ApplyChanges />

#### Step 7 - Seed and Query the database

```typescript copy filename="src/index.ts"
import 'dotenv/config';
import { eq } from 'drizzle-orm';
import { drizzle } from 'drizzle-orm/sqlite-cloud';
import { usersTable } from './db/schema';

async function main() {
  const db = drizzle();

  const user: typeof usersTable.$inferInsert = {
    name: 'John',
    age: 30,
    email: 'john@example.com',
  };

  await db.insert(usersTable).values(user);
  console.log('New user created!')

  const users = await db.select().from(usersTable);
  console.log('Getting all users from the database: ', users)
  /*
  const users: {
    id: number;
    name: string;
    age: number;
    email: string;
  }[]
  */

  await db
    .update(usersTable)
    .set({
      age: 31,
    })
    .where(eq(usersTable.email, user.email));
  console.log('User info updated!')

  await db.delete(usersTable).where(eq(usersTable.email, user.email));
  console.log('User deleted!')
}

main();
```

#### Step 8 - Run index.ts file

<RunFile/>


Source: https://orm.drizzle.team/docs/get-started/sqlite-existing

import Npm from '@mdx/Npm.astro';
import Npx from '@mdx/Npx.astro';
import Callout from '@mdx/Callout.astro';
import Prerequisites from "@mdx/Prerequisites.astro";
import CodeTabs from "@mdx/CodeTabs.astro";
import WhatsNextPostgres from "@mdx/WhatsNextPostgres.astro";
import Breadcrumbs from '@mdx/Breadcrumbs.astro';
import FileStructure from '@mdx/get-started/FileStructure.mdx';
import InstallPackages from '@mdx/get-started/InstallPackages.mdx';
import SetupConfig from '@mdx/get-started/sqlite/SetupConfig.mdx';
import TransferCode from '@mdx/get-started/TransferCode.mdx';
import QueryDatabase from '@mdx/get-started/QueryDatabase.mdx';
import QueryDatabaseUpdated from '@mdx/get-started/QueryDatabaseUpdated.mdx';
import RunFile from '@mdx/get-started/RunFile.mdx';
import ApplyChanges from '@mdx/get-started/sqlite/ApplyChanges.mdx';
import SetupEnv from '@mdx/get-started/SetupEnv.mdx';
import IntrospectSqlite from '@mdx/get-started/sqlite/IntrospectSqlite.mdx';
import ConnectLibsql from '@mdx/get-started/sqlite/ConnectLibsql.mdx';
import UpdateSchema from '@mdx/get-started/sqlite/UpdateSchema.mdx';

<Breadcrumbs/>

# Get Started with Drizzle and SQLite in existing project

<Prerequisites>  
  - **dotenv** - package for managing environment variables - [read here](https://www.npmjs.com/package/dotenv)
  - **tsx** - package for running TypeScript files - [read here](https://tsx.hirok.io/)
  - **libsql** - a fork of SQLite optimized for low query latency, making it suitable for global applications - [read here](https://docs.turso.tech/libsql)
</Prerequisites>

<FileStructure />

#### Step 1 - Install required packages

<InstallPackages lib='@libsql/client'/>

#### Step 2 - Setup connection variables

<SetupEnv env_variable='DB_FILE_NAME' />

<Callout type='info' title='important'>
For example, if you want to create an SQLite database file in the root of your project for testing purposes, you need to use `file:` before the actual filename, as this is the format required by `LibSQL`, like this:
```plaintext copy
DB_FILE_NAME=file:local.db
```
You can check the **[LibSQL docs](https://docs.turso.tech/sdk/ts/reference#local-development)** for more info.
</Callout>

#### Step 3 - Setup Drizzle config file

<SetupConfig dialect='sqlite' env_variable='DB_FILE_NAME'/>

#### Step 4 - Introspect your database

<IntrospectSqlite/>

#### Step 5 - Transfer code to your actual schema file

<TransferCode/>

#### Step 6 - Connect Drizzle ORM to the database

<ConnectLibsql/>

#### Step 7 - Query the database

<QueryDatabase dialect='libsql' env_variable='DB_FILE_NAME' />

#### Step 8 - Run index.ts file

<RunFile/>

#### Step 9 - Update your table schema (optional)

<UpdateSchema/>

#### Step 9 - Applying changes to the database (optional)

<ApplyChanges/>

#### Step 10 - Query the database with a new field (optional)

<QueryDatabaseUpdated dialect='libsql' env_variable='DB_FILE_NAME' />

Source: https://orm.drizzle.team/docs/get-started/sqlite-new

import Npm from '@mdx/Npm.astro';
import Npx from '@mdx/Npx.astro';
import Callout from '@mdx/Callout.astro';
import Prerequisites from "@mdx/Prerequisites.astro";
import CodeTabs from "@mdx/CodeTabs.astro";
import WhatsNextPostgres from "@mdx/WhatsNextPostgres.astro";
import Breadcrumbs from '@mdx/Breadcrumbs.astro';
import FileStructure from '@mdx/get-started/FileStructure.mdx';
import InstallPackages from '@mdx/get-started/InstallPackages.mdx';
import SetupConfig from '@mdx/get-started/sqlite/SetupConfig.mdx';
import TransferCode from '@mdx/get-started/TransferCode.mdx';
import QueryDatabase from '@mdx/get-started/QueryDatabase.mdx';
import QueryDatabaseUpdated from '@mdx/get-started/QueryDatabaseUpdated.mdx';
import RunFile from '@mdx/get-started/RunFile.mdx';
import ApplyChanges from '@mdx/get-started/sqlite/ApplyChanges.mdx';
import SetupEnv from '@mdx/get-started/SetupEnv.mdx';
import CreateTable from '@mdx/get-started/sqlite/CreateTable.mdx';
import ConnectLibsql from '@mdx/get-started/sqlite/ConnectLibsql.mdx';

<Breadcrumbs/>

# Get Started with Drizzle and SQLite

<Prerequisites>  
  - **dotenv** - package for managing environment variables - [read here](https://www.npmjs.com/package/dotenv)
  - **tsx** - package for running TypeScript files - [read here](https://tsx.hirok.io/)
  - **libsql** - a fork of SQLite optimized for low query latency, making it suitable for global applications - [read here](https://docs.turso.tech/libsql)
</Prerequisites>

Drizzle has native support for SQLite connections with the `libsql`, `node:sqlite` and `better-sqlite3` drivers.

We will use `libsql` for this get started example. But if you want to find more ways to connect to SQLite check
our [SQLite Connection](/docs/sqlite/get-started-sqlite) page 

<FileStructure />

#### Step 1 - Install required packages
<InstallPackages lib='@libsql/client'/>

#### Step 2 - Setup connection variables

<SetupEnv env_variable='DB_FILE_NAME' />

<Callout type='info' title='important'>
For example, if you want to create an SQLite database file in the root of your project for testing purposes, you need to use `file:` before the actual filename, as this is the format required by `LibSQL`, like this:
```plaintext copy
DB_FILE_NAME=file:local.db
```
You can check the **[LibSQL docs](https://docs.turso.tech/sdk/ts/reference#local-development)** for more info.
</Callout>

#### Step 3 - Connect Drizzle ORM to the database

<ConnectLibsql/>

#### Step 4 - Create a table

<CreateTable/>

#### Step 5 - Setup Drizzle config file

<SetupConfig dialect='sqlite' env_variable='DB_FILE_NAME'/>

#### Step 6 - Applying changes to the database

<ApplyChanges />

#### Step 7 - Seed and Query the database

<QueryDatabase dialect='libsql' env_variable='DB_FILE_NAME'/>

#### Step 8 - Run index.ts file

<RunFile/>

Source: https://orm.drizzle.team/docs/get-started/supabase-existing

import Tab from '@mdx/Tab.astro';
import Tabs from '@mdx/Tabs.astro';
import Npm from "@mdx/Npm.astro";
import Callout from '@mdx/Callout.astro';
import Steps from '@mdx/Steps.astro';
import AnchorCards from '@mdx/AnchorCards.astro';
import Breadcrumbs from '@mdx/Breadcrumbs.astro';
import CodeTabs from "@mdx/CodeTabs.astro";
import Prerequisites from "@mdx/Prerequisites.astro";
import IntrospectPostgreSQL from '@mdx/get-started/postgresql/IntrospectPostgreSQL.mdx';
import FileStructure from '@mdx/get-started/FileStructure.mdx';
import InstallPackages from '@mdx/get-started/InstallPackages.mdx';
import SetupConfig from '@mdx/get-started/SetupConfig.mdx';
import SetupEnv from '@mdx/get-started/SetupEnv.mdx';
import TransferCode from '@mdx/get-started/TransferCode.mdx';
import ApplyChanges from '@mdx/get-started/ApplyChanges.mdx';
import RunFile from '@mdx/get-started/RunFile.mdx';
import ConnectSupabase from '@mdx/get-started/postgresql/ConnectSupabase.mdx'
import QueryDatabase from '@mdx/get-started/QueryDatabase.mdx';
import QueryDatabaseUpdated from '@mdx/get-started/QueryDatabaseUpdated.mdx';
import UpdateSchema from '@mdx/get-started/postgresql/UpdateSchema.mdx';

<Breadcrumbs/>

# Get Started with Drizzle and Supabase in existing project

<Prerequisites>
  - **dotenv** - package for managing environment variables - [read here](https://www.npmjs.com/package/dotenv)
  - **tsx** - package for running TypeScript files - [read here](https://tsx.hirok.io/)
  - **Supabase** - open source Firebase alternative - [read here](https://supabase.com/)
</Prerequisites>

<FileStructure/>

#### Step 1 - Install **postgres** package
<InstallPackages lib='postgres'/>

#### Step 2 - Setup connection variables

<SetupEnv env_variable='DATABASE_URL' />

#### Step 3 - Setup Drizzle config file

<SetupConfig dialect='postgresql' env_variable='DATABASE_URL'/>

#### Step 4 - Introspect your database

<IntrospectPostgreSQL/>

#### Step 5 - Transfer code to your actual schema file

<TransferCode/>

#### Step 6 - Connect Drizzle ORM to the database

<ConnectSupabase/>

#### Step 7 - Query the database

<QueryDatabase dialect='postgres-js' env_variable='DATABASE_URL'/>

#### Step 8 - Run index.ts file

<RunFile/>

#### Step 9 - Update your table schema (optional)

<UpdateSchema/>

#### Step 10 - Applying changes to the database (optional)

<ApplyChanges />

#### Step 11 - Query the database with a new field (optional)

<QueryDatabaseUpdated dialect='postgres-js' env_variable='DATABASE_URL' />

Source: https://orm.drizzle.team/docs/get-started/supabase-new

import Tab from '@mdx/Tab.astro';
import Tabs from '@mdx/Tabs.astro';
import Npm from "@mdx/Npm.astro";
import Callout from '@mdx/Callout.astro';
import Steps from '@mdx/Steps.astro';
import AnchorCards from '@mdx/AnchorCards.astro';
import Breadcrumbs from '@mdx/Breadcrumbs.astro';
import Prerequisites from "@mdx/Prerequisites.astro";
import CodeTabs from "@mdx/CodeTabs.astro";
import FileStructure from '@mdx/get-started/FileStructure.mdx';
import InstallPackages from '@mdx/get-started/InstallPackages.mdx';
import ConnectSupabase from '@mdx/get-started/postgresql/ConnectSupabase.mdx'
import CreateTable from '@mdx/get-started/postgresql/CreateTable.mdx'
import SetupConfig from '@mdx/get-started/SetupConfig.mdx';
import ApplyChanges from '@mdx/get-started/ApplyChanges.mdx';
import RunFile from '@mdx/get-started/RunFile.mdx';
import QueryDatabase from '@mdx/get-started/QueryDatabase.mdx';
import SetupEnv from '@mdx/get-started/SetupEnv.mdx';

<Breadcrumbs/>

# Get Started with Drizzle and Supabase

<Prerequisites>
  - **dotenv** - package for managing environment variables - [read here](https://www.npmjs.com/package/dotenv)
  - **tsx** - package for running TypeScript files - [read here](https://tsx.hirok.io/)
  - **Supabase** - open source Firebase alternative - [read here](https://supabase.com/)
</Prerequisites>

<FileStructure/>

#### Step 1 - Install **postgres** package
<InstallPackages lib='postgres'/>

#### Step 2 - Setup connection variables

<SetupEnv env_variable='DATABASE_URL' />

#### Step 3 - Connect Drizzle ORM to the database

<ConnectSupabase/>

#### Step 4 - Create a table

<CreateTable />

#### Step 5 - Setup Drizzle config file

<SetupConfig dialect='postgresql' env_variable='DATABASE_URL'/>

#### Step 6 - Applying changes to the database

<ApplyChanges />

#### Step 7 - Seed and Query the database

<QueryDatabase dialect='postgres-js' env_variable='DATABASE_URL'/>

#### Step 8 - Run index.ts file

<RunFile/>

Source: https://orm.drizzle.team/docs/get-started/tidb-existing

import Npm from '@mdx/Npm.astro';
import Callout from '@mdx/Callout.astro';
import Prerequisites from "@mdx/Prerequisites.astro";
import CodeTabs from "@mdx/CodeTabs.astro";
import WhatsNextPostgres from "@mdx/WhatsNextPostgres.astro";
import Breadcrumbs from '@mdx/Breadcrumbs.astro';
import FileStructure from '@mdx/get-started/FileStructure.mdx';
import InstallPackages from '@mdx/get-started/InstallPackages.mdx';
import SetupEnv from '@mdx/get-started/SetupEnv.mdx';
import ConnectTiDB from '@mdx/get-started/mysql/ConnectTiDB.mdx';
import CreateTable from '@mdx/get-started/mysql/CreateTable.mdx';
import UpdateSchema from '@mdx/get-started/mysql/UpdateSchema.mdx';
import IntrospectMySQL from '@mdx/get-started/mysql/IntrospectMySQL.mdx';
import QueryDatabase from '@mdx/get-started/QueryDatabase.mdx';
import QueryDatabaseUpdated from '@mdx/get-started/QueryDatabaseUpdated.mdx';
import ApplyChanges from '@mdx/get-started/mysql/ApplyChanges.mdx';
import RunFile from '@mdx/get-started/RunFile.mdx';
import SetupConfig from '@mdx/get-started/mysql/SetupConfig.mdx';
import TransferCode from '@mdx/get-started/TransferCode.mdx';

<Breadcrumbs/>

# Get Started with Drizzle and TiDB in existing project

<Prerequisites>  
  - **dotenv** - package for managing environment variables - [read here](https://www.npmjs.com/package/dotenv)
  - **tsx** - package for running TypeScript files - [read here](https://tsx.hirok.io/)
  - **TiDB** - The Distributed SQL Database by PingCAP - [read here](https://www.pingcap.com/)
  - **serverless-js** - package for serverless and edge compute platforms that require HTTP external connections - [read here](https://github.com/tidbcloud/serverless-js)
</Prerequisites>

<FileStructure/>

#### Step 1 - Install **@tidbcloud/serverless** package

<InstallPackages lib='@tidbcloud/serverless'/>

#### Step 2 - Setup connection variables

<SetupEnv env_variable='DATABASE_URL' />

#### Step 3 - Setup Drizzle config file

<SetupConfig dialect='mysql' env_variable='DATABASE_URL'/>

#### Step 4 - Introspect your database

<IntrospectMySQL/>

#### Step 5 - Transfer code to your actual schema file

<TransferCode/>

#### Step 6 - Connect Drizzle ORM to the database

<ConnectTiDB/>

#### Step 7 - Query the database

<QueryDatabase dialect='tidb-serverless' env_variable='DATABASE_URL'/>

#### Step 8 - Run index.ts file

<RunFile/>

#### Step 9 - Update your table schema (optional)

<UpdateSchema/>

#### Step 10 - Applying changes to the database (optional)

<ApplyChanges/>

#### Step 11 - Query the database with a new field (optional)

<QueryDatabaseUpdated dialect='tidb-serverless' env_variable='DATABASE_URL' />

Source: https://orm.drizzle.team/docs/get-started/tidb-new

import Npm from '@mdx/Npm.astro';
import Callout from '@mdx/Callout.astro';
import Prerequisites from "@mdx/Prerequisites.astro";
import CodeTabs from "@mdx/CodeTabs.astro";
import WhatsNextPostgres from "@mdx/WhatsNextPostgres.astro";
import Breadcrumbs from '@mdx/Breadcrumbs.astro';
import FileStructure from '@mdx/get-started/FileStructure.mdx';
import InstallPackages from '@mdx/get-started/InstallPackages.mdx';
import SetupEnv from '@mdx/get-started/SetupEnv.mdx';
import ConnectTiDB from '@mdx/get-started/mysql/ConnectTiDB.mdx';
import CreateTable from '@mdx/get-started/mysql/CreateTable.mdx';
import QueryDatabase from '@mdx/get-started/QueryDatabase.mdx';
import ApplyChanges from '@mdx/get-started/mysql/ApplyChanges.mdx';
import RunFile from '@mdx/get-started/RunFile.mdx';
import SetupConfig from '@mdx/get-started/mysql/SetupConfig.mdx';

<Breadcrumbs/>

# Get Started with Drizzle and TiDB

<Prerequisites>  
  - **dotenv** - package for managing environment variables - [read here](https://www.npmjs.com/package/dotenv)
  - **tsx** - package for running TypeScript files - [read here](https://tsx.hirok.io/)
  - **TiDB** - The Distributed SQL Database by PingCAP - [read here](https://www.pingcap.com/)
  - **serverless-js** - package for serverless and edge compute platforms that require HTTP external connections - [read here](https://github.com/tidbcloud/serverless-js)
</Prerequisites>

<Callout title='important' type='warning'>
For this tutorial, we will use the `@tidbcloud/serverless` driver to make **HTTP** calls. If you need to
connect to TiDB through TCP, you can refer to our [MySQL Get Started](/docs/get-started/mysql-new) page
</Callout>

<FileStructure/>

#### Step 1 - Install **@tidbcloud/serverless** package

<InstallPackages lib='@tidbcloud/serverless'/>

#### Step 2 - Setup connection variables

<SetupEnv env_variable='DATABASE_URL' />

#### Step 3 - Connect Drizzle ORM to the database

<ConnectTiDB/>

#### Step 4 - Create a table

<CreateTable/>

#### Step 5 - Setup Drizzle config file

<SetupConfig dialect='mysql' env_variable='DATABASE_URL'/>

#### Step 6 - Applying changes to the database

<ApplyChanges />

#### Step 7 - Seed and Query the database

<QueryDatabase dialect='tidb-serverless' env_variable='DATABASE_URL'/>

#### Step 8 - Run index.ts file

<RunFile/>

Source: https://orm.drizzle.team/docs/get-started/turso-database-existing

import Tab from '@mdx/Tab.astro';
import Tabs from '@mdx/Tabs.astro';
import Npm from "@mdx/Npm.astro";
import Callout from '@mdx/Callout.astro';
import Steps from '@mdx/Steps.astro';
import AnchorCards from '@mdx/AnchorCards.astro';
import Breadcrumbs from '@mdx/Breadcrumbs.astro';
import CodeTabs from "@mdx/CodeTabs.astro";
import Prerequisites from "@mdx/Prerequisites.astro";
import IntrospectSQLite from '@mdx/get-started/sqlite/IntrospectSqlite.mdx';
import FileStructure from '@mdx/get-started/FileStructure.mdx';
import InstallPackages from '@mdx/get-started/InstallPackages.mdx';
import SetupConfig from '@mdx/get-started/sqlite/SetupConfig.mdx';
import SetupEnv from '@mdx/get-started/SetupEnv.mdx';
import TransferCode from '@mdx/get-started/TransferCode.mdx';
import ApplyChanges from '@mdx/get-started/sqlite/ApplyChanges.mdx';
import RunFile from '@mdx/get-started/RunFile.mdx';
import ConnectTursoDatabase from '@mdx/get-started/sqlite/ConnectTursoDatabase.mdx';
import QueryDatabase from '@mdx/get-started/QueryDatabase.mdx';
import QueryDatabaseUpdated from '@mdx/get-started/QueryDatabaseUpdated.mdx';
import UpdateSchema from '@mdx/get-started/sqlite/UpdateSchema.mdx';

<Breadcrumbs/>

# Get Started with Drizzle and Turso Database in existing project

<Prerequisites>
  - **dotenv** - package for managing environment variables - [read here](https://www.npmjs.com/package/dotenv)
  - **tsx** - package for running TypeScript files - [read here](https://tsx.hirok.io/)
  - Turso Database - [website](https://docs.turso.tech/introduction)
  - Turso Database driver - [website](https://docs.turso.tech/connect/javascript) & [GitHub](https://github.com/tursodatabase/turso/tree/main/bindings/javascript)
</Prerequisites>

<FileStructure/>

#### Step 1 - Install required package
<Npm>
    drizzle-orm@rc @tursodatabase/database dotenv
    -D drizzle-kit@rc tsx
</Npm>

#### Step 2 - Setup connection variables

<SetupEnv env_variable='DB_FILE_NAME' />

<Callout type='info' title='important'>
For example, if you want to create an SQLite database file in the root of your project for testing purposes, you can use this example:
```plaintext copy
DB_FILE_NAME=mydb.sqlite
```
</Callout>

#### Step 3 - Setup Drizzle config file

<SetupConfig dialect='sqlite' env_variable='DB_FILE_NAME'/>

#### Step 4 - Introspect your database

<IntrospectSQLite/>

#### Step 5 - Transfer code to your actual schema file

<TransferCode/>

#### Step 6 - Connect Drizzle ORM to the database

<ConnectTursoDatabase/>

#### Step 7 - Query the database

```typescript copy filename="src/index.ts"
import 'dotenv/config';
import { eq } from 'drizzle-orm';
import { drizzle } from 'drizzle-orm/tursodatabase/database';
import { usersTable } from './db/schema';

async function main() {
  const db = drizzle();

  const user: typeof usersTable.$inferInsert = {
    name: 'John',
    age: 30,
    email: 'john@example.com',
  };

  await db.insert(usersTable).values(user);
  console.log('New user created!')

  const users = await db.select().from(usersTable);
  console.log('Getting all users from the database: ', users)
  /*
  const users: {
    id: number;
    name: string;
    age: number;
    email: string;
  }[]
  */

  await db
    .update(usersTable)
    .set({
      age: 31,
    })
    .where(eq(usersTable.email, user.email));
  console.log('User info updated!')

  await db.delete(usersTable).where(eq(usersTable.email, user.email));
  console.log('User deleted!')
}

main();
```

#### Step 8 - Run index.ts file

<RunFile/>

#### Step 9 - Update your table schema (optional)

<UpdateSchema/>

#### Step 10 - Applying changes to the database (optional)

<ApplyChanges />

#### Step 11 - Query the database with a new field (optional)

```typescript copy filename="src/index.ts"
import 'dotenv/config';
import { eq } from 'drizzle-orm';
import { drizzle } from 'drizzle-orm/tursodatabase/database';
import { usersTable } from './db/schema';

async function main() {
  const db = drizzle();

  const user: typeof usersTable.$inferInsert = {
    name: 'John',
    age: 30,
    email: 'john@example.com',
    phone: '123-456-7890',
  };

  await db.insert(usersTable).values(user);
  console.log('New user created!')

  const users = await db.select().from(usersTable);
  console.log('Getting all users from the database: ', users)
  /*
  const users: {
    id: number;
    name: string;
    age: number;
    email: string;
    phone: string | null;
  }[]
  */

  await db
    .update(usersTable)
    .set({
      age: 31,
    })
    .where(eq(usersTable.email, user.email));
  console.log('User info updated!')

  await db.delete(usersTable).where(eq(usersTable.email, user.email));
  console.log('User deleted!')
}

main();
```


Source: https://orm.drizzle.team/docs/get-started/turso-database-new

import Tab from '@mdx/Tab.astro';
import Tabs from '@mdx/Tabs.astro';
import Npm from "@mdx/Npm.astro";
import Callout from '@mdx/Callout.astro';
import Steps from '@mdx/Steps.astro';
import AnchorCards from '@mdx/AnchorCards.astro';
import Breadcrumbs from '@mdx/Breadcrumbs.astro';
import Prerequisites from "@mdx/Prerequisites.astro";
import CodeTabs from "@mdx/CodeTabs.astro";
import FileStructure from '@mdx/get-started/FileStructure.mdx';
import InstallPackages from '@mdx/get-started/InstallPackages.mdx';
import ConnectTursoDatabase from '@mdx/get-started/sqlite/ConnectTursoDatabase.mdx'
import CreateTable from '@mdx/get-started/sqlite/CreateTable.mdx'
import SetupConfig from '@mdx/get-started/sqlite/SetupConfig.mdx';
import ApplyChanges from '@mdx/get-started/sqlite/ApplyChanges.mdx';
import RunFile from '@mdx/get-started/RunFile.mdx';
import QueryDatabase from '@mdx/get-started/QueryDatabase.mdx';
import SetupEnv from '@mdx/get-started/SetupEnv.mdx';

<Breadcrumbs/>

# Get Started with Drizzle and Turso Database

<Prerequisites>
  - **dotenv** - package for managing environment variables - [read here](https://www.npmjs.com/package/dotenv)
  - **tsx** - package for running TypeScript files - [read here](https://tsx.hirok.io/)
  - Turso Database - [website](https://docs.turso.tech/introduction)
  - Turso Database driver - [website](https://docs.turso.tech/connect/javascript) & [GitHub](https://github.com/tursodatabase/turso/tree/main/bindings/javascript)
</Prerequisites>

<FileStructure/>

#### Step 1 - Install required package
<Npm>
    drizzle-orm@rc @tursodatabase/database dotenv
    -D drizzle-kit@rc tsx
</Npm>

#### Step 2 - Setup connection variables

<SetupEnv env_variable='DB_FILE_NAME' />

<Callout type='info' title='important'>
For example, if you want to create an SQLite database file in the root of your project for testing purposes, you can use this example:
```plaintext copy
DB_FILE_NAME=mydb.sqlite
```
</Callout>

#### Step 3 - Connect Drizzle ORM to the database

<ConnectTursoDatabase/>

#### Step 4 - Create a table

<CreateTable />

#### Step 5 - Setup Drizzle config file

<SetupConfig dialect='sqlite' env_variable='DB_FILE_NAME'/>

#### Step 6 - Applying changes to the database

<ApplyChanges />

#### Step 7 - Seed and Query the database

```typescript copy filename="src/index.ts"
import 'dotenv/config';
import { eq } from 'drizzle-orm';
import { drizzle } from 'drizzle-orm/tursodatabase/database';
import { usersTable } from './db/schema';

async function main() {
  const db = drizzle();

  const user: typeof usersTable.$inferInsert = {
    name: 'John',
    age: 30,
    email: 'john@example.com',
  };

  await db.insert(usersTable).values(user);
  console.log('New user created!')

  const users = await db.select().from(usersTable);
  console.log('Getting all users from the database: ', users)
  /*
  const users: {
    id: number;
    name: string;
    age: number;
    email: string;
  }[]
  */

  await db
    .update(usersTable)
    .set({
      age: 31,
    })
    .where(eq(usersTable.email, user.email));
  console.log('User info updated!')

  await db.delete(usersTable).where(eq(usersTable.email, user.email));
  console.log('User deleted!')
}

main();
```

#### Step 8 - Run index.ts file

<RunFile/>


Source: https://orm.drizzle.team/docs/get-started/turso-existing

import Npm from '@mdx/Npm.astro';
import Npx from '@mdx/Npx.astro';
import Callout from '@mdx/Callout.astro';
import Prerequisites from "@mdx/Prerequisites.astro";
import CodeTabs from "@mdx/CodeTabs.astro";
import WhatsNextPostgres from "@mdx/WhatsNextPostgres.astro";
import Breadcrumbs from '@mdx/Breadcrumbs.astro';
import FileStructure from '@mdx/get-started/FileStructure.mdx';
import InstallPackages from '@mdx/get-started/InstallPackages.mdx';
import SetupConfig from '@mdx/get-started/sqlite/SetupConfig.mdx';
import TransferCode from '@mdx/get-started/TransferCode.mdx';
import QueryDatabase from '@mdx/get-started/QueryDatabase.mdx';
import QueryDatabaseUpdated from '@mdx/get-started/QueryDatabaseUpdated.mdx';
import RunFile from '@mdx/get-started/RunFile.mdx';
import ApplyChanges from '@mdx/get-started/sqlite/ApplyChanges.mdx';
import SetupEnv from '@mdx/get-started/SetupEnv.mdx';
import IntrospectSqlite from '@mdx/get-started/sqlite/IntrospectSqlite.mdx';
import ConnectLibsql from '@mdx/get-started/sqlite/ConnectLibsql.mdx';
import UpdateSchema from '@mdx/get-started/sqlite/UpdateSchema.mdx';
import QueryTurso from '@mdx/get-started/sqlite/QueryTurso.mdx';
import QueryTursoUpdated from '@mdx/get-started/sqlite/QueryTursoUpdated.mdx';
import LibsqlTable from '@mdx/LibsqlTable.mdx';
import LibsqlTabs from '@mdx/LibsqlTabs.mdx';

<Breadcrumbs/>

# Get Started with Drizzle and Turso Cloud in existing project

<Prerequisites>  
  - **dotenv** - package for managing environment variables - [read here](https://www.npmjs.com/package/dotenv)
  - **tsx** - package for running TypeScript files - [read here](https://tsx.hirok.io/)
  - **turso** - SQLite for Production - [read here](https://turso.tech/)
  - **libsql** - a fork of SQLite optimized for low query latency, making it suitable for global applications - [read here](https://docs.turso.tech/libsql)
</Prerequisites>

<FileStructure />

#### Step 1 - Install required packages

<InstallPackages lib='@libsql/client'/>

#### Step 2 - Setup connection variables

Create a `.env` file in the root of your project and add you Turso database url and auth token:

```plaintext copy
TURSO_DATABASE_URL=
TURSO_AUTH_TOKEN=
```

<Callout type='info' title='important'>
If you don't know your `TURSO_DATABASE_URL` and `TURSO_AUTH_TOKEN` values, you can refer to the LibSQL Driver SDK tutorial. 
Check it out [here](https://docs.turso.tech/sdk/ts/quickstart), then return with all the values generated and added to the `.env` file
</Callout>

#### Step 3 - Setup Drizzle config file

**Drizzle config** - a configuration file that is used by [Drizzle Kit](/docs/kit-overview) and contains all the information about your database connection, migration folder and schema files.

Create a `drizzle.config.ts` file in the root of your project and add the following content:

```typescript copy filename="drizzle.config.ts"
import 'dotenv/config';
import { defineConfig } from 'drizzle-kit';

export default defineConfig({
  out: './drizzle',
  schema: './src/db/schema.ts',
  dialect: 'turso',
  dbCredentials: {
    url: process.env.TURSO_DATABASE_URL,
    authToken: process.env.TURSO_AUTH_TOKEN,
  },
});
```

#### Step 4 - Introspect your database

<IntrospectSqlite/>

#### Step 5 - Transfer code to your actual schema file

<TransferCode/>

#### Step 6 - Connect Drizzle ORM to the database
Drizzle has native support for all @libsql/client driver variations:

<LibsqlTable />
<br/>
<LibsqlTabs />

Create a `index.ts` file in the `src` directory and initialize the connection:

```typescript copy
import 'dotenv/config';
import { drizzle } from 'drizzle-orm/libsql';

// You can specify any property from the libsql connection options
const db = drizzle({ 
  connection: { 
    url: process.env.TURSO_DATABASE_URL!, 
    authToken: process.env.TURSO_AUTH_TOKEN!
  }
});
```

If you need to provide your existing driver:

```typescript copy
import 'dotenv/config';
import { drizzle } from 'drizzle-orm/libsql';
import { createClient } from '@libsql/client';

const client = createClient({ 
  url: process.env.TURSO_DATABASE_URL!, 
  authToken: process.env.TURSO_AUTH_TOKEN!
});

const db = drizzle({ client });
```

#### Step 7 - Query the database

<QueryTurso/>

#### Step 8 - Run index.ts file

<RunFile/>

#### Step 9 - Update your table schema (optional)

<UpdateSchema/>

#### Step 9 - Applying changes to the database (optional)

<ApplyChanges/>

#### Step 10 - Query the database with a new field (optional)

<QueryTursoUpdated />

Source: https://orm.drizzle.team/docs/get-started/turso-new

import Npm from '@mdx/Npm.astro';
import Npx from '@mdx/Npx.astro';
import Callout from '@mdx/Callout.astro';
import Prerequisites from "@mdx/Prerequisites.astro";
import CodeTabs from "@mdx/CodeTabs.astro";
import WhatsNextPostgres from "@mdx/WhatsNextPostgres.astro";
import Breadcrumbs from '@mdx/Breadcrumbs.astro';
import FileStructure from '@mdx/get-started/FileStructure.mdx';
import InstallPackages from '@mdx/get-started/InstallPackages.mdx';
import SetupConfig from '@mdx/get-started/sqlite/SetupConfig.mdx';
import TransferCode from '@mdx/get-started/TransferCode.mdx';
import QueryTurso from '@mdx/get-started/sqlite/QueryTurso.mdx';
import QueryDatabaseUpdated from '@mdx/get-started/QueryDatabaseUpdated.mdx';
import RunFile from '@mdx/get-started/RunFile.mdx';
import ApplyChanges from '@mdx/get-started/sqlite/ApplyChanges.mdx';
import SetupEnv from '@mdx/get-started/SetupEnv.mdx';
import CreateTable from '@mdx/get-started/sqlite/CreateTable.mdx';
import ConnectLibsql from '@mdx/get-started/sqlite/ConnectLibsql.mdx';
import LibsqlTable from '@mdx/LibsqlTable.mdx';
import LibsqlTabs from '@mdx/LibsqlTabs.mdx';

<Breadcrumbs/>

# Get Started with Drizzle and Turso Cloud

<Prerequisites>  
  - **dotenv** - package for managing environment variables - [read here](https://www.npmjs.com/package/dotenv)
  - **tsx** - package for running TypeScript files - [read here](https://tsx.hirok.io/)
  - **turso** - SQLite for Production - [read here](https://turso.tech/)
  - **libsql** - a fork of SQLite optimized for low query latency, making it suitable for global applications - [read here](https://docs.turso.tech/libsql)
</Prerequisites>

<FileStructure />

#### Step 1 - Install required packages
<InstallPackages lib='@libsql/client'/>

#### Step 2 - Setup connection variables

Create a `.env` file in the root of your project and add you Turso database url and auth token:

```plaintext copy
TURSO_DATABASE_URL=
TURSO_AUTH_TOKEN=
```

<Callout type='info' title='important'>
If you don't know your `TURSO_DATABASE_URL` and `TURSO_AUTH_TOKEN` values, you can refer to the LibSQL Driver SDK tutorial. 
Check it out [here](https://docs.turso.tech/sdk/ts/quickstart), then return with all the values generated and added to the `.env` file
</Callout>

#### Step 3 - Connect Drizzle ORM to the database
Drizzle has native support for all @libsql/client driver variations:

<LibsqlTable />
<br/>
<LibsqlTabs />

Create a `index.ts` file in the `src` directory and initialize the connection:

```typescript copy
import 'dotenv/config';
import { drizzle } from 'drizzle-orm/libsql';

// You can specify any property from the libsql connection options
const db = drizzle({ 
  connection: { 
    url: process.env.TURSO_DATABASE_URL!, 
    authToken: process.env.TURSO_AUTH_TOKEN!
  }
});
```

If you need to provide your existing driver:
```typescript copy
import 'dotenv/config';
import { drizzle } from 'drizzle-orm/libsql';
import { createClient } from '@libsql/client';

const client = createClient({ 
  url: process.env.TURSO_DATABASE_URL!, 
  authToken: process.env.TURSO_AUTH_TOKEN!
});
const db = drizzle({ client });
```

#### Step 4 - Create a table

<CreateTable/>

#### Step 5 - Setup Drizzle config file

**Drizzle config** - a configuration file that is used by [Drizzle Kit](/docs/kit-overview) and contains all the information about your database connection, migration folder and schema files.

Create a `drizzle.config.ts` file in the root of your project and add the following content:

```typescript copy filename="drizzle.config.ts"
import 'dotenv/config';
import { defineConfig } from 'drizzle-kit';

export default defineConfig({
  out: './drizzle',
  schema: './src/db/schema.ts',
  dialect: 'turso',
  dbCredentials: {
    url: process.env.TURSO_DATABASE_URL,
    authToken: process.env.TURSO_AUTH_TOKEN,
  },
});
```

#### Step 6 - Applying changes to the database

<ApplyChanges />

#### Step 7 - Seed and Query the database

<QueryTurso/>

#### Step 8 - Run index.ts file

<RunFile/>

Source: https://orm.drizzle.team/docs/get-started/vercel-existing

import Tab from '@mdx/Tab.astro';
import Tabs from '@mdx/Tabs.astro';
import Npm from "@mdx/Npm.astro";
import Callout from '@mdx/Callout.astro';
import Steps from '@mdx/Steps.astro';
import AnchorCards from '@mdx/AnchorCards.astro';
import Breadcrumbs from '@mdx/Breadcrumbs.astro';
import CodeTabs from "@mdx/CodeTabs.astro";
import Prerequisites from "@mdx/Prerequisites.astro";
import IntrospectPostgreSQL from '@mdx/get-started/postgresql/IntrospectPostgreSQL.mdx';
import FileStructure from '@mdx/get-started/FileStructure.mdx';
import InstallPackages from '@mdx/get-started/InstallPackages.mdx';
import SetupConfig from '@mdx/get-started/SetupConfig.mdx';
import SetupEnv from '@mdx/get-started/SetupEnv.mdx';
import TransferCode from '@mdx/get-started/TransferCode.mdx';
import ApplyChanges from '@mdx/get-started/ApplyChanges.mdx';
import RunFile from '@mdx/get-started/RunFile.mdx';
import ConnectVercel from '@mdx/get-started/postgresql/ConnectVercel.mdx'
import QueryDatabase from '@mdx/get-started/QueryDatabase.mdx';
import QueryDatabaseUpdated from '@mdx/get-started/QueryDatabaseUpdated.mdx';
import UpdateSchema from '@mdx/get-started/postgresql/UpdateSchema.mdx';

<Breadcrumbs/>

# Get Started with Drizzle and Vercel Postgres in existing project

<Prerequisites>
  - **dotenv** - package for managing environment variables - [read here](https://www.npmjs.com/package/dotenv)
  - **tsx** - package for running TypeScript files - [read here](https://tsx.hirok.io/)
  - **Vercel Postgres database** - [read here](https://vercel.com/docs/storage/vercel-postgres)
  - **Vercel Postgres driver** - [read here](https://vercel.com/docs/storage/vercel-postgres/sdk) & [GitHub](https://github.com/vercel/storage/tree/main/packages/postgres)
</Prerequisites>

<FileStructure/>

#### Step 1 - Install required package
<InstallPackages lib='@vercel/postgres'/>

#### Step 2 - Setup connection variables

<SetupEnv env_variable='POSTGRES_URL' />

<Callout title='warning'>
It's important to name the variable `POSTGRES_URL` for Vercel Postgres.

In the Vercel Postgres storage tab, you can find the `.env.local` tab and copy the `POSTGRES_URL` variable
</Callout>

#### Step 3 - Setup Drizzle config file

<SetupConfig dialect='postgresql' env_variable='POSTGRES_URL'/>

#### Step 4 - Introspect your database

<IntrospectPostgreSQL/>

#### Step 5 - Transfer code to your actual schema file

<TransferCode/>

#### Step 6 - Connect Drizzle ORM to the database

<ConnectVercel/>

#### Step 7 - Query the database

```typescript copy filename="src/index.ts"
import 'dotenv/config';
import { eq } from 'drizzle-orm';
import { drizzle } from 'drizzle-orm/vercel-postgres';
import { usersTable } from './db/schema';

async function main() {
  const db = drizzle();

  const user: typeof usersTable.$inferInsert = {
    name: 'John',
    age: 30,
    email: 'john@example.com',
  };

  await db.insert(usersTable).values(user);
  console.log('New user created!')

  const users = await db.select().from(usersTable);
  console.log('Getting all users from the database: ', users)
  /*
  const users: {
    id: number;
    name: string;
    age: number;
    email: string;
  }[]
  */

  await db
    .update(usersTable)
    .set({
      age: 31,
    })
    .where(eq(usersTable.email, user.email));
  console.log('User info updated!')

  await db.delete(usersTable).where(eq(usersTable.email, user.email));
  console.log('User deleted!')
}

main();
```

#### Step 8 - Run index.ts file

<RunFile/>

#### Step 9 - Update your table schema (optional)

<UpdateSchema/>

#### Step 10 - Applying changes to the database (optional)

<ApplyChanges />

#### Step 11 - Query the database with a new field (optional)

```typescript copy filename="src/index.ts"
import 'dotenv/config';
import { eq } from 'drizzle-orm';
import { drizzle } from 'drizzle-orm/vercel-postgres';
import { usersTable } from './db/schema';

async function main() {
  const db = drizzle();

  const user: typeof usersTable.$inferInsert = {
    name: 'John',
    age: 30,
    email: 'john@example.com',
    phone: '123-456-7890',
  };

  await db.insert(usersTable).values(user);
  console.log('New user created!')

  const users = await db.select().from(usersTable);
  console.log('Getting all users from the database: ', users)
  /*
  const users: {
    id: number;
    name: string;
    age: number;
    email: string;
    phone: string | null;
  }[]
  */

  await db
    .update(usersTable)
    .set({
      age: 31,
    })
    .where(eq(usersTable.email, user.email));
  console.log('User info updated!')

  await db.delete(usersTable).where(eq(usersTable.email, user.email));
  console.log('User deleted!')
}

main();
```

Source: https://orm.drizzle.team/docs/get-started/vercel-new

import Tab from '@mdx/Tab.astro';
import Tabs from '@mdx/Tabs.astro';
import Npm from "@mdx/Npm.astro";
import Callout from '@mdx/Callout.astro';
import Steps from '@mdx/Steps.astro';
import AnchorCards from '@mdx/AnchorCards.astro';
import Breadcrumbs from '@mdx/Breadcrumbs.astro';
import Prerequisites from "@mdx/Prerequisites.astro";
import CodeTabs from "@mdx/CodeTabs.astro";
import FileStructure from '@mdx/get-started/FileStructure.mdx';
import InstallPackages from '@mdx/get-started/InstallPackages.mdx';
import ConnectVercel from '@mdx/get-started/postgresql/ConnectVercel.mdx'
import CreateTable from '@mdx/get-started/postgresql/CreateTable.mdx'
import SetupConfig from '@mdx/get-started/SetupConfig.mdx';
import ApplyChanges from '@mdx/get-started/ApplyChanges.mdx';
import RunFile from '@mdx/get-started/RunFile.mdx';
import QueryDatabase from '@mdx/get-started/QueryDatabase.mdx';
import SetupEnv from '@mdx/get-started/SetupEnv.mdx';

<Breadcrumbs/>

# Get Started with Drizzle and Vercel Postgres

<Prerequisites>
  - **dotenv** - package for managing environment variables - [read here](https://www.npmjs.com/package/dotenv)
  - **tsx** - package for running TypeScript files - [read here](https://tsx.hirok.io/)
  - **Vercel Postgres database** - [read here](https://vercel.com/docs/storage/vercel-postgres)
  - **Vercel Postgres driver** - [read here](https://vercel.com/docs/storage/vercel-postgres/sdk) & [GitHub](https://github.com/vercel/storage/tree/main/packages/postgres)
</Prerequisites>

<FileStructure/>

#### Step 1 - Install required package
<InstallPackages lib='@vercel/postgres'/>

#### Step 2 - Setup connection variables

<SetupEnv env_variable='POSTGRES_URL' />

<Callout title='warning'>
It's important to name the variable `POSTGRES_URL` for Vercel Postgres.

In the Vercel Postgres storage tab, you can find the `.env.local` tab and copy the `POSTGRES_URL` variable
</Callout>

#### Step 3 - Connect Drizzle ORM to the database

<ConnectVercel/>

#### Step 4 - Create a table

<CreateTable />

#### Step 5 - Setup Drizzle config file

<SetupConfig dialect='postgresql' env_variable='POSTGRES_URL'/>

#### Step 6 - Applying changes to the database

<ApplyChanges />

#### Step 7 - Seed and Query the database

```typescript copy filename="src/index.ts"
import 'dotenv/config';
import { eq } from 'drizzle-orm';
import { drizzle } from 'drizzle-orm/vercel-postgres';
import { usersTable } from './db/schema';

async function main() {
  const db = drizzle();

  const user: typeof usersTable.$inferInsert = {
    name: 'John',
    age: 30,
    email: 'john@example.com',
  };

  await db.insert(usersTable).values(user);
  console.log('New user created!')

  const users = await db.select().from(usersTable);
  console.log('Getting all users from the database: ', users)
  /*
  const users: {
    id: number;
    name: string;
    age: number;
    email: string;
  }[]
  */

  await db
    .update(usersTable)
    .set({
      age: 31,
    })
    .where(eq(usersTable.email, user.email));
  console.log('User info updated!')

  await db.delete(usersTable).where(eq(usersTable.email, user.email));
  console.log('User deleted!')
}

main();
```

#### Step 8 - Run index.ts file

<RunFile/>

Source: https://orm.drizzle.team/docs/get-started/xata-existing

import Tab from '@mdx/Tab.astro';
import Tabs from '@mdx/Tabs.astro';
import Npm from "@mdx/Npm.astro";
import Callout from '@mdx/Callout.astro';
import Steps from '@mdx/Steps.astro';
import AnchorCards from '@mdx/AnchorCards.astro';
import Breadcrumbs from '@mdx/Breadcrumbs.astro';
import CodeTabs from "@mdx/CodeTabs.astro";
import Prerequisites from "@mdx/Prerequisites.astro";
import IntrospectPostgreSQL from '@mdx/get-started/postgresql/IntrospectPostgreSQL.mdx';
import FileStructure from '@mdx/get-started/FileStructure.mdx';
import InstallPackages from '@mdx/get-started/InstallPackages.mdx';
import SetupConfig from '@mdx/get-started/SetupConfig.mdx';
import SetupEnv from '@mdx/get-started/SetupEnv.mdx';
import TransferCode from '@mdx/get-started/TransferCode.mdx';
import ApplyChanges from '@mdx/get-started/ApplyChanges.mdx';
import RunFile from '@mdx/get-started/RunFile.mdx';
import ConnectXata from '@mdx/get-started/postgresql/ConnectXata.mdx'
import QueryDatabase from '@mdx/get-started/QueryDatabase.mdx';
import QueryDatabaseUpdated from '@mdx/get-started/QueryDatabaseUpdated.mdx';
import UpdateSchema from '@mdx/get-started/postgresql/UpdateSchema.mdx';

<Breadcrumbs/>

# Get Started with Drizzle and Xata in existing project

<Prerequisites>
  - **dotenv** - package for managing environment variables - [read here](https://www.npmjs.com/package/dotenv)
  - **tsx** - package for running TypeScript files - [read here](https://tsx.hirok.io/)
  - **Xata Postgres database** - [read here](https://xata.io/documentation)
</Prerequisites>

<FileStructure/>

#### Step 1 - Install **postgres** package
<InstallPackages lib='postgres'/>

#### Step 2 - Setup connection variables

<SetupEnv env_variable='DATABASE_URL' />

You can obtain a connection string by following the [Xata documentation](https://xata.io/documentation/getting-started).

#### Step 3 - Setup Drizzle config file

<SetupConfig dialect='postgresql' env_variable='DATABASE_URL'/>

#### Step 4 - Introspect your database

<IntrospectPostgreSQL/>

#### Step 5 - Transfer code to your actual schema file

<TransferCode/>

#### Step 6 - Connect Drizzle ORM to the database

<ConnectXata/>

#### Step 7 - Query the database

<QueryDatabase dialect='postgres-js' env_variable='DATABASE_URL'/>

#### Step 8 - Run index.ts file

<RunFile/>

#### Step 9 - Update your table schema (optional)

<UpdateSchema/>

#### Step 10 - Applying changes to the database (optional)

<ApplyChanges />

#### Step 11 - Query the database with a new field (optional)

<QueryDatabaseUpdated dialect='postgres-js' env_variable='DATABASE_URL' />

Source: https://orm.drizzle.team/docs/get-started/xata-new

import Tab from '@mdx/Tab.astro';
import Tabs from '@mdx/Tabs.astro';
import Npm from "@mdx/Npm.astro";
import Callout from '@mdx/Callout.astro';
import Steps from '@mdx/Steps.astro';
import AnchorCards from '@mdx/AnchorCards.astro';
import Breadcrumbs from '@mdx/Breadcrumbs.astro';
import Prerequisites from "@mdx/Prerequisites.astro";
import CodeTabs from "@mdx/CodeTabs.astro";
import FileStructure from '@mdx/get-started/FileStructure.mdx';
import InstallPackages from '@mdx/get-started/InstallPackages.mdx';
import ConnectXata from '@mdx/get-started/postgresql/ConnectXata.mdx'
import CreateTable from '@mdx/get-started/postgresql/CreateTable.mdx'
import SetupConfig from '@mdx/get-started/SetupConfig.mdx';
import ApplyChanges from '@mdx/get-started/ApplyChanges.mdx';
import RunFile from '@mdx/get-started/RunFile.mdx';
import QueryDatabase from '@mdx/get-started/QueryDatabase.mdx';
import SetupEnv from '@mdx/get-started/SetupEnv.mdx';

<Breadcrumbs/>

# Get Started with Drizzle and Xata

<Prerequisites>
  - **dotenv** - package for managing environment variables - [read here](https://www.npmjs.com/package/dotenv)
  - **tsx** - package for running TypeScript files - [read here](https://tsx.hirok.io/)
  - **Xata Postgres database** - [read here](https://xata.io/documentation)
</Prerequisites>

<FileStructure/>

#### Step 1 - Install **postgres** package
<InstallPackages lib='postgres'/>

#### Step 2 - Setup connection variables

<SetupEnv env_variable='DATABASE_URL' />

You can obtain a connection string by following the [Xata documentation](https://xata.io/docs/quickstart).

#### Step 3 - Connect Drizzle ORM to the database

<ConnectXata/>

#### Step 4 - Create a table

<CreateTable />

#### Step 5 - Setup Drizzle config file

<SetupConfig dialect='postgresql' env_variable='DATABASE_URL'/>

#### Step 6 - Applying changes to the database

<ApplyChanges />

#### Step 7 - Seed and Query the database

<QueryDatabase dialect='postgres-js' env_variable='DATABASE_URL'/>

#### Step 8 - Run index.ts file

<RunFile/>

Source: https://orm.drizzle.team/docs/gotchas

import CodeTab from "@mdx/CodeTab.astro";
import CodeTabs from "@mdx/CodeTabs.astro";
import Section from "@mdx/Section.astro";
import Tab from "@mdx/Tab.astro";
import Tabs from "@mdx/Tabs.astro";
import Callout from "@mdx/Callout.astro";

# Drizzle gotchas

This will be a library of `gotchas` with Drizzle use cases

Source: https://orm.drizzle.team/docs/graphql

import Tab from '@mdx/Tab.astro';
import Tabs from '@mdx/Tabs.astro';
import Callout from '@mdx/Callout.astro';
import CodeTab from '@mdx/CodeTab.astro';
import CodeTabs from '@mdx/CodeTabs.astro';
import Npm from '@mdx/Npm.astro';

# drizzle-graphql

Create a GraphQL server from a Drizzle schema in one line, and easily enhance it with custom queries and mutations.

## Quick start

Make sure your `drizzle-orm` version is at least `0.30.9`, and update if needed:
<Npm>drizzle-orm@latest</Npm>

### Apollo Server

<Npm>drizzle-graphql @apollo/server graphql</Npm>

<CodeTabs items={['server.ts', 'schema.ts']}>
<CodeTab>
```ts copy {1, 10}
import { buildSchema } from 'drizzle-graphql';
import { drizzle } from 'drizzle-orm/...';
import client from './db';
import { ApolloServer } from '@apollo/server';
import { startStandaloneServer } from '@apollo/server/standalone';

import * as dbSchema from './schema';

const db = drizzle({ client, schema: dbSchema });

const { schema } = buildSchema(db);

const server = new ApolloServer({ schema });
const { url } = await startStandaloneServer(server);

console.log(`🚀 Server ready at ${url}`);
```
</CodeTab>
<CodeTab>
```typescript copy
import { integer, serial, text, pgTable } from 'drizzle-orm/pg-core';
import { relations } from 'drizzle-orm';

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

export const usersRelations = relations(users, ({ many }) => ({
  posts: many(posts),
}));

export const posts = pgTable('posts', {
  id: serial('id').primaryKey(),
  content: text('content').notNull(),
  authorId: integer('author_id').notNull(),
});

export const postsRelations = relations(posts, ({ one }) => ({
  author: one(users, { fields: [posts.authorId], references: [users.id] }),
}));
```
</CodeTab>
</CodeTabs>

### GraphQL Yoga

<Npm>drizzle-graphql graphql-yoga graphql</Npm>

<CodeTabs items={['server.ts', 'schema.ts']}>
<CodeTab>
```ts copy {1, 10}
import { buildSchema } from 'drizzle-graphql';
import { drizzle } from 'drizzle-orm/...';
import { createYoga } from 'graphql-yoga';
import { createServer } from 'node:http';

import * as dbSchema from './schema';

const db = drizzle({ schema: dbSchema });

const { schema } = buildSchema(db);

const yoga = createYoga({ schema });
const server = createServer(yoga);

server.listen(4000, () => {
  console.info('Server is running on http://localhost:4000/graphql');
});
```
</CodeTab>
<CodeTab>
```typescript copy
import { integer, serial, text, pgTable } from 'drizzle-orm/pg-core';
import { relations } from 'drizzle-orm';

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

export const usersRelations = relations(users, ({ many }) => ({
  posts: many(posts),
}));

export const posts = pgTable('posts', {
  id: serial('id').primaryKey(),
  content: text('content').notNull(),
  authorId: integer('author_id').notNull(),
});

export const postsRelations = relations(posts, ({ one }) => ({
  author: one(users, { fields: [posts.authorId], references: [users.id] }),
}));
```
</CodeTab>
</CodeTabs>

## Customizing schema

<Callout type='info' emoji='ℹ️'>
`buildSchema()` produces schema and types using standard `graphql` SDK, so its output is compatible with any library that supports it.
</Callout>

If you want to customize your schema, you can use `entities` object to build your own new schema:

<CodeTabs items={['server.ts', 'schema.ts']}>
<CodeTab>
```ts {1, 11}
import { buildSchema } from 'drizzle-graphql';
import { drizzle } from 'drizzle-orm/...';
import { GraphQLList, GraphQLNonNull, GraphQLObjectType, GraphQLSchema } from 'graphql';
import { createYoga } from 'graphql-yoga';
import { createServer } from 'node:http';

import * as dbSchema from './schema';

const db = drizzle({ schema: dbSchema });

const { entities } = buildSchema(db);

// You can customize which parts of queries or mutations you want
const schema = new GraphQLSchema({
  query: new GraphQLObjectType({
    name: 'Query',
    fields: {
      // Select only wanted queries out of all generated
      users: entities.queries.users,
      customer: entities.queries.customersSingle,

      // Create a custom one
      customUsers: {
        // You can reuse and customize types from original schema
        type: new GraphQLList(new GraphQLNonNull(entities.types.UsersItem)),
        args: {
          // You can reuse inputs as well
          where: {
            type: entities.inputs.UsersFilters
          },
        },
        resolve: async (source, args, context, info) => {
          // Your custom logic goes here...
          const result = await db.select(schema.users).where()...

          return result;
        },
      },
    },
  }),
  // Same rules apply to mutations
  mutation: new GraphQLObjectType({
    name: 'Mutation',
    fields: entities.mutations,
  }),
  // In case you need types inside your schema
  types: [...Object.values(entities.types), ...Object.values(entities.inputs)],
});

const yoga = createYoga({
  schema,
});

const server = createServer(yoga);

server.listen(4000, () => {
  console.info('Server is running on http://localhost:4000/graphql');
})
```
</CodeTab>
<CodeTab>
```typescript copy
import { integer, serial, text, pgTable } from 'drizzle-orm/pg-core';
import { relations } from 'drizzle-orm';

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

export const usersRelations = relations(users, ({ many }) => ({
  posts: many(posts),
}));

export const posts = pgTable('posts', {
  id: serial('id').primaryKey(),
  content: text('content').notNull(),
  authorId: integer('author_id').notNull(),
});

export const postsRelations = relations(posts, ({ one }) => ({
  author: one(users, { fields: [posts.authorId], references: [users.id] }),
}));
```
</CodeTab>
</CodeTabs>


Source: https://orm.drizzle.team/docs/guides

import Guides from "@components/Guides.astro";

<Guides/>

Source: https://orm.drizzle.team/docs/guides/conditional-filters-in-query

import Section from "@mdx/Section.astro";
import IsSupportedChipGroup from "@mdx/IsSupportedChipGroup.astro";
import Prerequisites from "@mdx/Prerequisites.astro";

<IsSupportedChipGroup chips={{PostgreSQL: true, MySQL: true, SQLite: true, MSSQL: true, Cockroach: true}}/>

<Prerequisites>
- Get started with [PostgreSQL](/docs/get-started-postgresql), [MySQL](/docs/mysql/get-started-mysql), [SQLite](/docs/sqlite/get-started-sqlite), [MSSQL](/docs/mssql/get-started-mssql) and [Cockroach](/docs/cockroach/get-started-cockroach);
- [Select statement](/docs/select);
- [Filtering](/docs/select#filters) and [Filter operators](/docs/operators);
</Prerequisites>

To pass a conditional filter in query you can use `.where()` method and logical operator like below:

<Section>
```ts copy {9}
import { ilike } from 'drizzle-orm';

const db = drizzle(...)

const searchPosts = async (term?: string) => {
  await db
    .select()
    .from(posts)
    .where(term ? ilike(posts.title, term) : undefined);
};

await searchPosts();
await searchPosts('AI');
```


```sql
select * from posts;
select * from posts where title ilike 'AI';
```
</Section>

To combine conditional filters you can use `and()` or `or()` operators like below:

<Section>
```ts copy {7,8,9,10,11,12,13}
import { and, gt, ilike, inArray } from 'drizzle-orm';

const searchPosts = async (term?: string, categories: string[] = [], views = 0) => {
  await db
    .select()
    .from(posts)
    .where(
      and(
        term ? ilike(posts.title, term) : undefined,
        categories.length > 0 ? inArray(posts.category, categories) : undefined,
        views > 100 ? gt(posts.views, views) : undefined,
      ),
    );
};

await searchPosts();
await searchPosts('AI', ['Tech', 'Art', 'Science'], 200);
```

```sql
select * from posts;
select * from posts
  where (
    title ilike 'AI'
    and category in ('Tech', 'Science', 'Art')
    and views > 200
  );
```
</Section>

If you need to combine conditional filters in different part of the project you can create a variable, push filters and then use it in `.where()` method with `and()` or `or()` operators like below:

```ts copy {7,10}
import { SQL, ... } from 'drizzle-orm';

const searchPosts = async (filters: SQL[]) => {
  await db
    .select()
    .from(posts)
    .where(and(...filters));
};

const filters: SQL[] = [];
filters.push(ilike(posts.title, 'AI'));
filters.push(inArray(posts.category, ['Tech', 'Art', 'Science']));
filters.push(gt(posts.views, 200));

await searchPosts(filters);
```

Drizzle has useful and flexible API, which lets you create your custom solutions. This is how you can create a custom filter operator:

<Section>

```ts copy {5,14}
import { AnyColumn, ... } from 'drizzle-orm';

// length less than
const lenlt = (column: AnyColumn, value: number) => {
  return sql`length(${column}) < ${value}`;
};

const searchPosts = async (maxLen = 0, views = 0) => {
  await db
    .select()
    .from(posts)
    .where(
      and(
        maxLen ? lenlt(posts.title, maxLen) : undefined,
        views > 100 ? gt(posts.views, views) : undefined,
      ),
    );
};

await searchPosts(8);
await searchPosts(8, 200);
```

```sql
select * from posts where length(title) < 8;
select * from posts where (length(title) < 8 and views > 200);
```
</Section>

Drizzle filter operators are just SQL expressions under the hood. This is example of how `lt` operator is implemented in Drizzle:

```js
const lt = (left, right) => {
  return sql`${left} < ${bindIfParam(right, left)}`; // bindIfParam is internal magic function
};
```


Source: https://orm.drizzle.team/docs/guides/count-rows

import Section from "@mdx/Section.astro";
import Prerequisites from "@mdx/Prerequisites.astro";
import IsSupportedChipGroup from "@mdx/IsSupportedChipGroup.astro";
import CodeTabs from '@mdx/CodeTabs.astro';
import CodeTab from '@mdx/CodeTab.astro';
import Callout from '@mdx/Callout.astro';

<IsSupportedChipGroup chips={{PostgreSQL: true, MySQL: true, SQLite: true, MSSQL: true, Cockroach: true}}/>

<Prerequisites>
- Get started with [PostgreSQL](/docs/get-started-postgresql), [MySQL](/docs/mysql/get-started-mysql), [SQLite](/docs/sqlite/get-started-sqlite), [MSSQL](/docs/mssql/get-started-mssql) and [Cockroach](/docs/cockroach/get-started-cockroach)
- [Select statement](/docs/select)
- [Filters](/docs/operators) and [sql operator](/docs/sql)
- [Aggregations](/docs/select#aggregations) and [Aggregation helpers](/docs/select#aggregations-helpers)
- [Joins](/docs/joins)
</Prerequisites>

To count all rows in table you can use `count()` function or `sql` operator like below:

<CodeTabs items={["index.ts", "schema.ts"]}>
  <CodeTab>
    ```ts copy {6,9}
    import { count, sql } from 'drizzle-orm';
    import { products } from './schema';

    const db = drizzle(...);

    await db.select({ count: count() }).from(products);

    // Under the hood, the count() function casts its result to a number at runtime.
    await db.select({ count: sql`count(*)`.mapWith(Number) }).from(products);
    ```

    ```ts
    // result type
    type Result = {
      count: number;
    }[];
    ```

    ```sql
    select count(*) from products;
    ```
  </CodeTab>
  ```ts
  import { integer, pgTable, serial, text } from 'drizzle-orm/pg-core';

  export const products = pgTable('products', {
    id: serial('id').primaryKey(),
    name: text('name').notNull(),
    discount: integer('discount'),
    price: integer('price').notNull(),
  });
  ```
</CodeTabs>

To count rows where the specified column contains non-NULL values you can use `count()` function with a column:

<Section>
```ts copy {1}
await db.select({ count: count(products.discount) }).from(products);
```

```ts
// result type
type Result = {
  count: number;
}[];
```

```sql
select count("discount") from products;
```
</Section>

Drizzle has simple and flexible API, which lets you create your custom solutions. In PostgreSQL, MySQL and Cockroach `count()` function returns bigint, which is interpreted as string by their drivers, so it should be casted to integer:

<Section>
```ts copy {5,7,11,12}
import { AnyColumn, sql } from 'drizzle-orm';

const customCount = (column?: AnyColumn) => {
  if (column) {
    return sql<number>`cast(count(${column}) as integer)`; // In MySQL cast to unsigned integer
  } else {
    return sql<number>`cast(count(*) as integer)`; // In MySQL cast to unsigned integer
  }
};

await db.select({ count: customCount() }).from(products);
await db.select({ count: customCount(products.discount) }).from(products);
```

```sql
select cast(count(*) as integer) from products;
select cast(count("discount") as integer) from products;
```
</Section>

In SQLite and MSSQL, `count()` result returns as integer.

<Section>
```ts copy {3,4}
import { sql } from 'drizzle-orm';

await db.select({ count: sql<number>`count(*)` }).from(products);
await db.select({ count: sql<number>`count(${products.discount})` }).from(products);
```

```sql
select count(*) from products;
select count("discount") from products;
```
</Section>

<Callout type="warning">
By specifying `sql<number>`, you are telling Drizzle that the **expected** type of the field is `number`.<br />
If you specify it incorrectly (e.g. use `sql<string>` for a field that will be returned as a number), the runtime value won't match the expected type.
Drizzle cannot perform any type casts based on the provided type generic, because that information is not available at runtime.

If you need to apply runtime transformations to the returned value, you can use the [`.mapWith()`](/docs/sql#sqlmapwith) method.
</Callout>

To count rows that match a condition you can use `.where()` method:

<Section>
```ts copy {4,6}
import { count, gt } from 'drizzle-orm';

await db
  .select({ count: count() })
  .from(products)
  .where(gt(products.price, 100));
```

```sql
select count(*) from products where price > 100
```
</Section>

This is how you can use `count()` function with joins and aggregations:

<CodeTabs items={["index.ts", "schema.ts"]}>
	<CodeTab>
    ```ts copy {8,11,12,13}
    import { count, eq } from 'drizzle-orm';
    import { countries, cities } from './schema';

    // Count cities in each country
    await db
      .select({
        country: countries.name,
        citiesCount: count(cities.id),
      })
      .from(countries)
      .leftJoin(cities, eq(countries.id, cities.countryId))
      .groupBy(countries.id)
      .orderBy(countries.name);
    ```

    ```sql
    select countries.name, count("cities"."id") from countries
      left join cities on countries.id = cities.country_id
      group by countries.id
      order by countries.name;
    ```
  </CodeTab>
  ```ts
  import { integer, pgTable, serial, text } from 'drizzle-orm/pg-core';

  export const countries = pgTable('countries', {
    id: serial('id').primaryKey(),
    name: text('name').notNull(),
  });

  export const cities = pgTable('cities', {
    id: serial('id').primaryKey(),
    name: text('name').notNull(),
    countryId: integer('country_id').notNull().references(() => countries.id),
  });
  ```
</CodeTabs>


Source: https://orm.drizzle.team/docs/guides/cursor-based-pagination


import CodeTabs from '@mdx/CodeTabs.astro';
import CodeTab from '@mdx/CodeTab.astro';
import IsSupportedChipGroup from "@mdx/IsSupportedChipGroup.astro";
import Section from "@mdx/Section.astro";
import Prerequisites from "@mdx/Prerequisites.astro";

<IsSupportedChipGroup chips={{PostgreSQL: true, MySQL: true, SQLite: true, MSSQL: true, Cockroach: true}}/>

<Prerequisites>
- Get started with [PostgreSQL](/docs/get-started-postgresql), [MySQL](/docs/mysql/get-started-mysql), [SQLite](/docs/sqlite/get-started-sqlite), [MSSQL](/docs/mssql/get-started-mssql) and [Cockroach](/docs/cockroach/get-started-cockroach)
- [Select statement](/docs/select) with [order by clause](/docs/select#order-by)
- [Relational queries](/docs/rqb) with [order by clause](/docs/rqb#order-by)
- [Indices](/docs/indexes-constraints)
</Prerequisites>

This guide demonstrates how to implement `cursor-based` pagination in Drizzle:

<CodeTabs items={["index.ts", "schema.ts"]}>
  <CodeTab>
  ```ts copy {10,11,12}
  import { asc, gt } from 'drizzle-orm';
  import { users } from './schema';

  const db = drizzle(...);

  const nextUserPage = async (cursor?: number, pageSize = 3) => {
    await db
      .select()
      .from(users)
      .where(cursor ? gt(users.id, cursor) : undefined) // if cursor is provided, get rows after it
      .limit(pageSize) // the number of rows to return
      .orderBy(asc(users.id)); // ordering
  };

  // pass the cursor of the last row of the previous page (id)
  await nextUserPage(3);
  ```

  ```sql
  select * from users order by id asc limit 3;
  ```

  ```ts
  // next page, 4-6 rows returned
  [
    {
      id: 4,
      firstName: 'Brian',
      lastName: 'Brown',
      createdAt: 2024-03-08T12:34:55.182Z
    },
    {
      id: 5,
      firstName: 'Beth',
      lastName: 'Davis',
      createdAt: 2024-03-08T12:40:55.182Z
    },
    {
      id: 6,
      firstName: 'Charlie',
      lastName: 'Miller',
      createdAt: 2024-03-08T13:04:55.182Z
    }
  ]
  ```
  </CodeTab>
  <CodeTab>
  ```ts copy
  import { pgTable, serial, text, timestamp } from 'drizzle-orm/pg-core';

  export const users = pgTable('users', {
    id: serial('id').primaryKey(),
    firstName: text('first_name').notNull(),
    lastName: text('last_name').notNull(),
    createdAt: timestamp('created_at').notNull().defaultNow(),
  });
  ```

  ```plaintext
  +----+------------+------------+----------------------------+
  | id | first_name | last_name  |         created_at         |
  +----+------------+------------+----------------------------+
  |  1 | Alice      | Johnson    | 2024-03-08 12:23:55.251797 |
  +----+------------+------------+----------------------------+
  |  2 | Alex       | Smith      | 2024-03-08 12:25:55.182    |
  +----+------------+------------+----------------------------+
  |  3 | Aaron      | Williams   | 2024-03-08 12:28:55.182    |
  +----+------------+------------+----------------------------+
  |  4 | Brian      | Brown      | 2024-03-08 12:34:55.182    |
  +----+------------+------------+----------------------------+
  |  5 | Beth       | Davis      | 2024-03-08 12:40:55.182    |
  +----+------------+------------+----------------------------+
  |  6 | Charlie    | Miller     | 2024-03-08 13:04:55.182    |
  +----+------------+------------+----------------------------+
  |  7 | Clara      | Wilson     | 2024-03-08 13:22:55.182    |
  +----+------------+------------+----------------------------+
  |  8 | David      | Moore      | 2024-03-08 13:34:55.182    |
  +----+------------+------------+----------------------------+
  |  9 | Aaron      | Anderson   | 2024-03-08 12:40:33.677235 |
  +----+------------+------------+----------------------------+
  ```
  </CodeTab>

</CodeTabs>

If you need dynamic order by you can do like below:

```ts copy {6,8}
const nextUserPage = async (order: 'asc' | 'desc' = 'asc', cursor?: number, pageSize = 3) => {
  await db
    .select()
    .from(users)
    // cursor comparison
    .where(cursor ? (order === 'asc' ? gt(users.id, cursor) : lt(users.id, cursor)) : undefined)
    .limit(pageSize)
    .orderBy(order === 'asc' ? asc(users.id) : desc(users.id));
};

await nextUserPage();
await nextUserPage('asc', 3);
// descending order
await nextUserPage('desc');
await nextUserPage('desc', 7);
```

The main idea of this pagination is to use cursor as a pointer to a specific row in a dataset, indicating the end of the previous page. For correct ordering and cursor comparison, cursor should be unique and sequential.

If you need to order by a non-unique and non-sequential column, you can use multiple columns for cursor. This is how you can do it:

<Section>
```ts copy {14,15,16,17,18,19,22}
import { and, asc, eq, gt, or } from 'drizzle-orm';

const nextUserPage = async (
  cursor?: {
    id: number;
    firstName: string;
  },
  pageSize = 3,
) => {
  await db
    .select()
    .from(users)
    .where(
      cursor
        ? or(
            gt(users.firstName, cursor.firstName),
            and(eq(users.firstName, cursor.firstName), gt(users.id, cursor.id)),
          )
        : undefined,
    )
    .limit(pageSize)
    .orderBy(asc(users.firstName), asc(users.id));
};

// pass the cursor from previous page (id & firstName)
await nextUserPage({
  id: 2,
  firstName: 'Alex',
});
```

```sql
select * from users
  where (first_name > 'Alex' or (first_name = 'Alex' and id > 2))
  order by first_name asc, id asc limit 3;
```

```ts
// next page, 4-6 rows returned
[
  {
    id: 1,
    firstName: 'Alice',
    lastName: 'Johnson',
    createdAt: 2024-03-08T12:23:55.251Z
  },
  {
    id: 5,
    firstName: 'Beth',
    lastName: 'Davis',
    createdAt: 2024-03-08T12:40:55.182Z
  },
  {
    id: 4,
    firstName: 'Brian',
    lastName: 'Brown',
    createdAt: 2024-03-08T12:34:55.182Z
  }
]
```
</Section>

Make sure to create indices for the columns that you use for cursor to make query efficient.

<Section>
```ts copy {7,8}
import { index, ...imports } from 'drizzle-orm/pg-core';

export const users = pgTable('users', {
  // columns declaration
},
(t) => [
  index('first_name_index').on(t.firstName).asc(),
  index('first_name_and_id_index').on(t.firstName, t.id).asc(),
]);
```

```sql
-- As of now drizzle-kit only supports index name and on() param, so you have to add order manually
CREATE INDEX IF NOT EXISTS "first_name_index" ON "users" ("first_name" ASC);
CREATE INDEX IF NOT EXISTS "first_name_and_id_index" ON "users" ("first_name" ASC,"id" ASC);
```
</Section>

If you are using primary key which is not sequential (e.g. `UUIDv4`), you should add sequential column (e.g. `created_at` column) and use multiple cursor.
This is how you can do it:

<Section>
```ts copy {12,13,14,15,16,17,18,21}

const nextUserPage = async (
  cursor?: {
    id: string;
    createdAt: Date;
  },
  pageSize = 3,
) => {
  await db
    .select()
    .from(users)
    .where(
      // make sure to add indices for the columns that you use for cursor
      cursor
        ? or(
            gt(users.createdAt, cursor.createdAt),
            and(eq(users.createdAt, cursor.createdAt), gt(users.id, cursor.id)),
          )
        : undefined,
    )
    .limit(pageSize)
    .orderBy(asc(users.createdAt), asc(users.id));
};

// pass the cursor from previous page (id & createdAt)
await nextUserPage({
  id: '66ed00a4-c020-4dfd-a1ca-5d2e4e54d174',
  createdAt: new Date('2024-03-09T17:59:36.406Z'),
});
```
</Section>

Drizzle has useful relational queries API, that lets you easily implement `cursor-based` pagination:

```ts copy {7,8,9}
import * as schema from './db/schema';

const db = drizzle(..., { schema });

const nextUserPage = async (cursor?: number, pageSize = 3) => {
  await db.query.users.findMany({
    where: (users, { gt }) => (cursor ? gt(users.id, cursor) : undefined),
    orderBy: (users, { asc }) => asc(users.id),
    limit: pageSize,
  });
};

// next page, cursor of last row of the first page (id = 3)
await nextUserPage(3);
```

**Benefits** of `cursor-based` pagination: consistent query results, with no skipped or duplicated rows due to insert or delete operations, and greater efficiency compared to `limit/offset` pagination because it does not need to scan and skip previous rows to access the next page.

**Drawbacks** of `cursor-based` pagination: the inability to directly navigate to a specific page and complexity of implementation. Since you add more columns to the sort order, you'll need to add more filters to the `where` clause for the cursor comparison to ensure consistent pagination.

So, if you need to directly navigate to a specific page or you need simpler implementation of pagination, you should consider using [offset/limit](/docs/guides/limit-offset-pagination) pagination instead.


Source: https://orm.drizzle.team/docs/guides/d1-http-with-drizzle-kit


import Prerequisites from "@mdx/Prerequisites.astro";

<Prerequisites>
- [Drizzle Kit](/docs/kit-overview)
- [Drizzle Studio](/docs/kit-overview#drizzle-studio)
- [Drizzle Chrome Extension](https://chromewebstore.google.com/detail/drizzle-studio/mjkojjodijpaneehkgmeckeljgkimnmd)
- You should have installed `drizzle-kit@0.21.3` or higher
- You should have [Cloudflare account](https://dash.cloudflare.com/login), deployed [D1 database](https://developers.cloudflare.com/d1/) and token with D1 edit permissions
</Prerequisites>

To use Drizzle kit with Cloudflare D1 HTTP API, you need to configure the `drizzle.config.ts` file like this:

```ts copy filename="drizzle.config.ts" {7, 9-11}
import { defineConfig } from 'drizzle-kit';

export default defineConfig({
  schema: './src/schema.ts',
  out: './migrations',
  dialect: 'sqlite',
  driver: 'd1-http',
  dbCredentials: {
    accountId: process.env.CLOUDFLARE_ACCOUNT_ID!,
    databaseId: process.env.CLOUDFLARE_DATABASE_ID!,
    token: process.env.CLOUDFLARE_D1_TOKEN!,
  },
});
```

You can find `accountId`, `databaseId` and `token` in [Cloudflare dashboard](https://dash.cloudflare.com/login?).

1. To get `accountId` go to **Workers & Pages** -> **Overview** -> copy **Account ID** from the right sidebar.
2. To get `databaseId` open D1 database you want to connect to and copy **Database ID**.
3. To get `token` go to **My profile** -> **API Tokens** and create token with D1 edit permissions.

After you have configured `drizzle.config.ts` file, Drizzle Kit lets you run `migrate`, `push`, `introspect` and `studio` commands using Cloudflare D1 HTTP API.

You can also use [Drizzle Chrome Extension](https://chromewebstore.google.com/detail/drizzle-studio/mjkojjodijpaneehkgmeckeljgkimnmd) to browse Cloudflare D1 database directly in their admin panel.




Source: https://orm.drizzle.team/docs/guides/decrementing-a-value

import Section from "@mdx/Section.astro";
import IsSupportedChipGroup from "@mdx/IsSupportedChipGroup.astro";
import Prerequisites from "@mdx/Prerequisites.astro";

<IsSupportedChipGroup chips={{PostgreSQL: true, MySQL: true, SQLite: true, MSSQL: true, Cockroach: true}}/>

<Prerequisites>
- Get started with [PostgreSQL](/docs/get-started-postgresql), [MySQL](/docs/mysql/get-started-mysql), [SQLite](/docs/sqlite/get-started-sqlite), [MSSQL](/docs/mssql/get-started-mssql) and [Cockroach](/docs/cockroach/get-started-cockroach)
- [Update statement](/docs/update)
- [Filters](/docs/operators) and [sql operator](/docs/sql)
</Prerequisites>

To decrement a column value you can use `update().set()` method like below:

<Section>
```ts copy {8}
import { eq, sql } from 'drizzle-orm';

const db = drizzle(...)
  
await db
  .update(table)
  .set({
    counter: sql`${table.counter} - 1`,
  })
  .where(eq(table.id, 1));
```

```sql
update "table" set "counter" = "counter" - 1 where "id" = 1;
```
</Section>

Drizzle has simple and flexible API, which lets you easily create custom solutions. This is how you do custom decrement function:

```ts copy {4,10,11}
import { AnyColumn } from 'drizzle-orm';

const decrement = (column: AnyColumn, value = 1) => {
  return sql`${column} - ${value}`;
};

await db
  .update(table)
  .set({
    counter1: decrement(table.counter1),
    counter2: decrement(table.counter2, 10),
  })
  .where(eq(table.id, 1));
```


Source: https://orm.drizzle.team/docs/guides/empty-array-default-value


import Section from "@mdx/Section.astro";
import Prerequisites from "@mdx/Prerequisites.astro";

<Prerequisites>
- Get started with [PostgreSQL](/docs/get-started-postgresql), [MySQL](/docs/mysql/get-started-mysql) and [SQLite](/docs/sqlite/get-started-sqlite)
- Learn about column data types for [PostgreSQL](/docs/column-types), [MySQL](/docs/mysql/column-types) and [SQLite](/docs/sqlite/column-types)
- [sql operator](/docs/sql)
</Prerequisites>

### PostgreSQL

To set an empty array as a default value in PostgreSQL, you can use `sql` operator with `'{}'` or `ARRAY[]` syntax:

<Section>
```ts copy {10,14}
import { sql } from 'drizzle-orm';
import { pgTable, serial, text } from 'drizzle-orm/pg-core';

export const users = pgTable('users', {
  id: serial('id').primaryKey(),
  name: text('name').notNull(),
  tags1: text('tags1')
    .array()
    .notNull()
    .default(sql`'{}'::text[]`),
  tags2: text('tags2')
    .array()
    .notNull()
    .default(sql`ARRAY[]::text[]`),
});
```

```sql
CREATE TABLE IF NOT EXISTS "users" (
	"id" serial PRIMARY KEY NOT NULL,
	"name" text NOT NULL,
	"tags1" text[] DEFAULT '{}'::text[] NOT NULL,
	"tags2" text[] DEFAULT ARRAY[]::text[] NOT NULL
);
```
</Section>


### MySQL

MySQL doesn't have an array data type, but you can use `json` data type for the same purpose. To set an empty array as a default value in MySQL, you can use `JSON_ARRAY()` function or `sql` operator with `('[]')` syntax:

<Section>
```ts copy {7,11,15}
import { sql } from 'drizzle-orm';
import { json, mysqlTable, serial, varchar } from 'drizzle-orm/mysql-core';

export const users = mysqlTable('users', {
  id: serial('id').primaryKey(),
  name: varchar('name', { length: 255 }).notNull(),
  tags1: json('tags1').$type<string[]>().notNull().default([]),
  tags2: json('tags2')
    .$type<string[]>()
    .notNull()
    .default(sql`('[]')`), // the same as default([])
  tags3: json('tags3')
    .$type<string[]>()
    .notNull()
    .default(sql`(JSON_ARRAY())`),
});
```

```sql
CREATE TABLE `users` (
	`id` serial AUTO_INCREMENT NOT NULL,
	`name` varchar(255) NOT NULL,
	`tags1` json NOT NULL DEFAULT ('[]'),
	`tags2` json NOT NULL DEFAULT ('[]'),
	`tags3` json NOT NULL DEFAULT (JSON_ARRAY()),
	CONSTRAINT `users_id` PRIMARY KEY(`id`)
);
```
</Section>

The `mode` option defines how values are handled in the application. With `json` mode, values are treated as JSON object literal. 

You can specify `.$type<..>()` for json object inference, it will not check runtime values. It provides compile time protection for default values, insert and select schemas.

### SQLite

SQLite doesn't have an array data type, but you can use `text` data type for the same purpose. To set an empty array as a default value in SQLite, you can use `json_array()` function or `sql` operator with `'[]'` syntax:

<Section>
```ts copy {9,13}
import { sql } from 'drizzle-orm';
import { integer, sqliteTable, text } from 'drizzle-orm/sqlite-core';

export const users = sqliteTable('users', {
  id: integer('id').primaryKey(),
  tags1: text('tags1', { mode: 'json' })
    .notNull()
    .$type<string[]>()
    .default(sql`(json_array())`),
  tags2: text('tags2', { mode: 'json' })
    .notNull()
    .$type<string[]>()
    .default(sql`'[]'`),
});
```

```sql
CREATE TABLE `users` (
	`id` integer PRIMARY KEY NOT NULL,
	`tags1` text DEFAULT (json_array()) NOT NULL,
	`tags2` text DEFAULT '[]' NOT NULL
);
```
</Section>

The `mode` option defines how values are handled in the application. With `json` mode, values are treated as JSON object literal. 

You can specify `.$type<..>()` for json object inference, it will not check runtime values. It provides compile time protection for default values, insert and select schemas.


Source: https://orm.drizzle.team/docs/guides/full-text-search-with-generated-columns


import Section from "@mdx/Section.astro";
import Prerequisites from "@mdx/Prerequisites.astro";
import CodeTabs from '@mdx/CodeTabs.astro';
import CodeTab from '@mdx/CodeTab.astro';

<Prerequisites>
- Get started with [PostgreSQL](/docs/get-started-postgresql)
- [Select statement](/docs/select)
- [Indexes](/docs/indexes-constraints#indexes)
- [sql operator](/docs/sql) 
- [Full-text search](/learn/guides/postgresql-full-text-search)
- [Generated columns](/docs/generated-columns)
</Prerequisites>

This guide demonstrates how to implement full-text search in PostgreSQL with Drizzle and generated columns. A generated column is a special column that is always computed from other columns. It is useful because you don't have to compute the value of the column every time you query the table:

<CodeTabs items={["schema.ts", "migration.sql"]}>
  <CodeTab>
  ```ts copy {18,19,20,23}
import { SQL, sql } from 'drizzle-orm';
import { index, pgTable, serial, text, customType } from 'drizzle-orm/pg-core';

export const tsvector = customType<{
  data: string;
}>({
  dataType() {
    return `tsvector`;
  },
});

export const posts = pgTable(
  'posts',
  {
    id: serial('id').primaryKey(),
    title: text('title').notNull(),
    body: text('body').notNull(),
    bodySearch: tsvector('body_search')
      .notNull()
      .generatedAlwaysAs((): SQL => sql`to_tsvector('english', ${posts.body})`),
  },
  (t) => [
    index('idx_body_search').using('gin', t.bodySearch),
  ]
);
  ```
  </CodeTab>
  ```sql
CREATE TABLE "posts" (
	"id" serial PRIMARY KEY NOT NULL,
	"title" text NOT NULL,
	"body" text NOT NULL,
	"body_search" "tsvector" GENERATED ALWAYS AS (to_tsvector('english', "posts"."body")) STORED NOT NULL
);
--> statement-breakpoint
CREATE INDEX "idx_body_search" ON "posts" USING gin ("body_search");
  ```
</CodeTabs>

When you insert a row into a table, the value of a generated column is computed from an expression that you provide when you create the column:

<Section>
```ts 
import { posts } from './schema';

const db = drizzle(...);

const body = "Golden leaves cover the quiet streets as a crisp breeze fills the air, bringing the scent of rain and the promise of change"

await db.insert(posts).values({
    body,
    title: "The Beauty of Autumn",
  }
).returning();
```

```json
[
  {
    id: 1,
    title: 'The Beauty of Autumn',
    body: 'Golden leaves cover the quiet streets as a crisp breeze fills the air, bringing the scent of rain and the promise of change',
    bodySearch: "'air':13 'breez':10 'bring':14 'chang':23 'cover':3 'crisp':9 'fill':11 'golden':1 'leav':2 'promis':21 'quiet':5 'rain':18 'scent':16 'street':6"
  }
]
```
</Section>

This is how you can implement full-text search with generated columns in PostgreSQL with Drizzle ORM.  The `@@` operator is used for direct matches:

<Section>
```ts copy {6}
const searchParam = "bring";

await db
  .select()
  .from(posts)
  .where(sql`${posts.bodySearch} @@ to_tsquery('english', ${searchParam})`);
```

```sql
select * from posts where body_search @@ to_tsquery('english', 'bring');
```
</Section>

This is more advanced schema with a generated column. The `search` column is generated from the `title` and `body` columns and `setweight()` function is used to assign different weights to the columns for full-text search.
This is typically used to mark entries coming from different parts of a document, such as title versus body.

<CodeTabs items={["schema.ts", "migration.sql"]}>
  <CodeTab>
  ```ts copy {18,19,20,21,22,23,24,28}
import { SQL, sql } from 'drizzle-orm';
import { index, pgTable, serial, text, customType } from 'drizzle-orm/pg-core';

export const tsvector = customType<{
  data: string;
}>({
  dataType() {
    return `tsvector`;
  },
});

export const posts = pgTable(
 'posts',
 {
   id: serial('id').primaryKey(),
   title: text('title').notNull(),
   body: text('body').notNull(),
   search: tsvector('search')
     .notNull()
     .generatedAlwaysAs(
        (): SQL =>
         sql`setweight(to_tsvector('english', ${posts.title}), 'A')
          ||
          setweight(to_tsvector('english', ${posts.body}), 'B')`,
     ),
  },
  (t) => [
    index('idx_search').using('gin', t.search),
  ],
);
  ```
  </CodeTab>
  ```sql
CREATE TABLE "posts" (
	"id" serial PRIMARY KEY NOT NULL,
	"title" text NOT NULL,
	"body" text NOT NULL,
	"search" "tsvector" GENERATED ALWAYS AS (setweight(to_tsvector('english', "posts"."title"), 'A')
          ||
          setweight(to_tsvector('english', "posts"."body"), 'B')) STORED NOT NULL
);
--> statement-breakpoint
CREATE INDEX "idx_search" ON "posts" USING gin ("search");
  ```
</CodeTabs>

This is how you can query the table with full-text search:

<Section>
```ts copy {6}
const search = 'travel';

await db
  .select()
  .from(posts)
  .where(sql`${posts.search} @@ to_tsquery('english', ${search})`);
```

```sql
select * from posts where search @@ to_tsquery('english', 'travel');
```
</Section>


Source: https://orm.drizzle.team/docs/guides/gel-ext-auth

import Prerequisites from "@mdx/Prerequisites.astro";
import Callout from "@mdx/Callout.astro";
import Npx from "@mdx/Npx.astro";

<Prerequisites>
- Get started with [Gel](/docs/get-started-gel)
- Using [drizzle-kit pull](/docs/drizzle-kit-pull)
</Prerequisites>

#### Step 1 - Define Gel auth schema

In `dbschema/default.esdl` file add a Gel schema with an auth extension

```esdl
using extension auth;

module default {
  global current_user := (
    assert_single((
      select User { id, username, email }
      filter .identity = global ext::auth::ClientTokenIdentity
    ))
  );

  type User {
    required identity: ext::auth::Identity;
    required username: str;
    required email: str;
  }
}
```

#### Step 2 - Push Gel schema to the database

Generate Gel migration file:
```bash
gel migration create
```

Apply Gel migrations to the database
```bash
gel migration apply
```

#### Step 3 - Setup Drizzle config file

**Drizzle config** - a configuration file that is used by [Drizzle Kit](/docs/kit-overview) and contains all the information about your database connection, migration folder and schema files.

Create a `drizzle.config.ts` file in the root of your project and add the following content:

```typescript copy filename="drizzle.config.ts"
import { defineConfig } from 'drizzle-kit';

export default defineConfig({
  dialect: 'gel',
  // Enable auth schema for drizzle-kit
  schemaFilter: ['ext::auth', 'public']
});
```

#### Step 4 - Pull Gel types to Drizzle schema

Pull your database schema:
<Npx>
drizzle-kit pull
</Npx>

Here is an example of the generated schema.ts file:

<Callout type="warning">
You'll get more than just the `Identity` table from `ext::auth`. Drizzle will pull in all the 
`auth` tables you can use. The example below showcases just one of them.
</Callout>

```ts
import { gelTable, uniqueIndex, uuid, text, gelSchema, timestamptz, foreignKey } from "drizzle-orm/gel-core"
import { sql } from "drizzle-orm"

export const extauth = gelSchema('ext::auth');

export const identityInExtauth = extauth.table('Identity', {
	id: uuid().default(sql`uuid_generate_v4()`).primaryKey().notNull(),
	createdAt: timestamptz('created_at').default(sql`(clock_timestamp())`).notNull(),
	issuer: text().notNull(),
	modifiedAt: timestamptz('modified_at').notNull(),
	subject: text().notNull(),
}, (table) => [
	uniqueIndex('6bc2dd19-bce4-5810-bb1b-7007afe97a11;schemaconstr').using(
		'btree',
		table.id.asc().nullsLast().op('uuid_ops'),
	),
]);

export const user = gelTable('User', {
	id: uuid().default(sql`uuid_generate_v4()`).primaryKey().notNull(),
	email: text().notNull(),
	identityId: uuid('identity_id').notNull(),
	username: text().notNull(),
}, (table) => [
	uniqueIndex('d504514c-26a7-11f0-b836-81aa188c0abe;schemaconstr').using(
		'btree',
		table.id.asc().nullsLast().op('uuid_ops'),
	),
	foreignKey({
		columns: [table.identityId],
		foreignColumns: [identityInExtauth.id],
		name: 'User_fk_identity',
	}),
]);
```

🎉 Now you can use the `auth` tables in your queries!

Source: https://orm.drizzle.team/docs/guides/include-or-exclude-columns


import Section from "@mdx/Section.astro";
import IsSupportedChipGroup from "@mdx/IsSupportedChipGroup.astro";
import Prerequisites from "@mdx/Prerequisites.astro";
import CodeTabs from '@mdx/CodeTabs.astro';
import CodeTab from '@mdx/CodeTab.astro';
import Callout from "@mdx/Callout.astro";

<IsSupportedChipGroup chips={{PostgreSQL: true, MySQL: true, SQLite: true, MSSQL: true, Cockroach: true}}/>

<Prerequisites>
- Get started with [PostgreSQL](/docs/get-started-postgresql), [MySQL](/docs/mysql/get-started-mysql), [SQLite](/docs/sqlite/get-started-sqlite), [MSSQL](/docs/mssql/get-started-mssql) and [Cockroach](/docs/cockroach/get-started-cockroach)
- [Select statement](/docs/select)
- [Get typed table columns](/docs/goodies#get-typed-table-columns)
- [Joins](/docs/joins)
- [Relational queries](/docs/rqb)
- [Partial select with relational queries](/docs/rqb#partial-fields-select)
</Prerequisites>

Drizzle has flexible API for including or excluding columns in queries. To include all columns you can use `.select()` method like this:

<CodeTabs items={["index.ts", "schema.ts"]}>
	<CodeTab>
    ```ts copy {5}
    import { posts } from './schema';

    const db = drizzle(...);

    await db.select().from(posts);
    ```

    ```ts
    // result type
    type Result = {
      id: number;
      title: string;
      content: string;
      views: number;
    }[];
    ```
  </CodeTab>

  ```ts copy
  import { integer, pgTable, serial, text } from 'drizzle-orm/pg-core';

  export const posts = pgTable('posts', {
    id: serial('id').primaryKey(),
    title: text('title').notNull(),
    content: text('content').notNull(),
    views: integer('views').notNull().default(0),
  });
	```
</CodeTabs>

To include specific columns you can use `.select()` method like this:

<Section>
  ```ts copy {1}
  await db.select({ title: posts.title }).from(posts);
  ```

  ```ts
  // result type
  type Result = {
    title: string;
  }[];
  ```
</Section>

To include all columns with extra columns you can use `getColumns()` utility function like this:

<Section>
  ```ts copy {5,6}
  import { getColumns, sql } from 'drizzle-orm';

  await db
    .select({
      ...getColumns(posts),
      titleLength: sql<number>`length(${posts.title})`,
    })
    .from(posts);
  ```

  ```ts
  // result type
  type Result = {
    id: number;
    title: string;
    content: string;
    views: number;
    titleLength: number;
  }[];
  ```
</Section>

To exclude columns you can use `getColumns()` utility function like this:

<Section>
  ```ts copy {3,5}
  import { getColumns } from 'drizzle-orm';

  const { content, ...rest } = getColumns(posts); // exclude "content" column

  await db.select({ ...rest }).from(posts); // select all other columns
  ```

  ```ts
  // result type
  type Result = {
    id: number;
    title: string;
    views: number;
  }[];
  ```
</Section>

This is how you can include or exclude columns with joins:

<CodeTabs items={["index.ts", "schema.ts"]}>
  <CodeTab>
    ```ts copy {5,9,10,11}
    import { eq, getColumns } from 'drizzle-orm';
    import { comments, posts, users } from './db/schema';

    // exclude "userId" and "postId" columns from "comments"
    const { userId, postId, ...rest } = getColumns(comments);

    await db
      .select({
        postId: posts.id, // include "id" column from "posts"
        comment: { ...rest }, // include all other columns
        user: users, // equivalent to getColumns(users)
      })
      .from(posts)
      .leftJoin(comments, eq(posts.id, comments.postId))
      .leftJoin(users, eq(users.id, posts.userId));
    ```

    ```ts
    // result type
    type Result = {
      postId: number;
      comment: {
        id: number;
        content: string;
        createdAt: Date;
      } | null;
      user: {
        id: number;
        name: string;
        email: string;
      } | null;
    }[];
    ```
  </CodeTab>

  ```ts copy
  import { integer, pgTable, serial, text, timestamp } from 'drizzle-orm/pg-core';

  export const users = pgTable('users', {
    id: serial('id').primaryKey(),
    name: text('name').notNull(),
    email: text('email').notNull(),
  });

  export const posts = pgTable('posts', {
    id: serial('id').primaryKey(),
    title: text('title').notNull(),
    content: text('content').notNull(),
    views: integer('views').notNull().default(0),
    userId: integer('user_id').notNull().references(() => users.id),
  });

  export const comments = pgTable('comments', {
    id: serial('id').primaryKey(),
    postId: integer('post_id').notNull().references(() => posts.id),
    userId: integer('user_id').notNull().references(() => users.id),
    content: text('content').notNull(),
    createdAt: timestamp('created_at').notNull().defaultNow(),
  });
  ```
</CodeTabs>

Drizzle has useful relational queries API, that lets you easily include or exclude columns in queries. This is how you can include all columns:

<CodeTabs items={["index.ts", "schema.ts", "relations.ts"]}>
  <CodeTab>
	```ts copy {5,7,8,9,12,13,14,17,18,19,20,21,22}
	import { relations } from './relations';

	const db = drizzle(..., { relations });

	await db.query.posts.findMany();
	```

	```ts
	// result type
	type Result = {
	  id: number;
	  title: string;
	  content: string;
	  views: number;
	}[]
	```
  </CodeTab>

  ```ts copy
  import { integer, pgTable, serial, text } from 'drizzle-orm/pg-core';

  export const posts = pgTable('posts', {
	id: serial('id').primaryKey(),
	title: text('title').notNull(),
	content: text('content').notNull(),
	views: integer('views').notNull().default(0),
  });
	```

  ```ts copy
  import { posts } from './schema.ts';

  export const relations = defineRelations({ posts });
	```
</CodeTabs>

This is how you can include specific columns using relational queries:

<Section>
  ```ts copy {2,3,4}
  await db.query.posts.findMany({
    columns: {
      title: true,
    },
  });
  ```

  ```ts
  // result type
  type Result = {
    title: string;
  }[]
  ```
</Section>

This is how you can include all columns with extra columns using relational queries:

<Section>
  ```ts copy {4,5,6}
  import { sql } from 'drizzle-orm';

  await db.query.posts.findMany({
    extras: {
      titleLength: (t) => sql<number>`length(${t.title})`.as("title_length"),
    },
  });
  ```

  ```ts
  // result type
  type Result = {
    id: number;
    title: string;
    content: string;
    views: number;
    titleLength: number;
  }[];
  ```
</Section>

This is how you can exclude columns using relational queries:

<Section>
  ```ts copy {2,3,4}
  await db.query.posts.findMany({
    columns: {
      content: false,
    },
  });
  ```

  ```ts
  // result type
  type Result = {
    id: number;
    title: string;
    views: number;
  }[]
  ```
</Section>

This is how you can include or exclude columns with relations using relational queries:

<CodeTabs items={["index.ts", "schema.ts", "relations.ts"]}>
  <CodeTab>
  ```ts copy {7,12,13,16}
  import { relations } from './relations';

  const db = drizzle(..., { relations });

  await db.query.posts.findMany({
    columns: {
      id: true, // include "id" column
    },
    with: {
      comments: {
        columns: {
          userId: false, // exclude "userId" column
          postId: false, // exclude "postId" column
        },
      },
      user: true, // include all columns from "users" table
    },
  });
  ```

  ```ts
  // result type
  type Result = {
    id: number;
    user: {
      id: number;
      name: string;
      email: string;
    };
    comments: {
      id: number;
      content: string;
      createdAt: Date;
    }[];
  }[]
  ```
  </CodeTab>

  ```ts copy
  import { integer, pgTable, serial, text, timestamp } from 'drizzle-orm/pg-core';

  export const users = pgTable('users', {
    id: serial('id').primaryKey(),
    name: text('name').notNull(),
    email: text('email').notNull(),
  });

  export const posts = pgTable('posts', {
    id: serial('id').primaryKey(),
    title: text('title').notNull(),
    content: text('content').notNull(),
    views: integer('views').notNull().default(0),
    userId: integer('user_id').notNull().references(() => users.id),
  });

  export const comments = pgTable('comments', {
    id: serial('id').primaryKey(),
    postId: integer('post_id').notNull().references(() => posts.id),
    userId: integer('user_id').notNull().references(() => users.id),
    content: text('content').notNull(),
    createdAt: timestamp('created_at').notNull().defaultNow(),
  });
  ```

	```ts copy
  import { defineRelations } from "drizzle-orm";
  import { comments, posts, users } from "./schema";
  
  export const relations = defineRelations({ users, posts, comments }, (r) => ({
    users: {
      posts: r.many.posts(),
      comments: r.many.comments(),
    },
    posts: {
      user: r.one.users({
        from: r.posts.userId,
        to: r.users.id,
		optional: false,
      }),
      comments: r.many.comments(),
    },
    comments: {
      post: r.one.posts({
        from: r.comments.postId,
        to: r.posts.id,
      }),
      user: r.one.users({
        from: r.comments.userId,
        to: r.users.id,
      }),
    },
  }));
	```
</CodeTabs>

This is how you can create custom solution for conditional select:

<CodeTabs items={["index.ts", "schema.ts"]}>
  <CodeTab>
    ```ts copy {7}
    import { posts } from './schema';

    const searchPosts = async (withTitle = false) => {
      return await db
        .select({
          id: posts.id,
          ...(withTitle && { title: posts.title }),
        })
        .from(posts);
    };

    await searchPosts();
    await searchPosts(true);
    ```

    ```ts
    // result type
    type Result = {
      id: number;
      title?: string | undefined;
    }[];
    ```
  </CodeTab>

  ```ts copy
  import { integer, pgTable, serial, text } from 'drizzle-orm/pg-core';

  export const posts = pgTable('posts', {
    id: serial('id').primaryKey(),
    title: text('title').notNull(),
    content: text('content').notNull(),
    views: integer('views').notNull().default(0),
  });
	```
</CodeTabs>


Source: https://orm.drizzle.team/docs/guides/incrementing-a-value

import Section from "@mdx/Section.astro";
import IsSupportedChipGroup from "@mdx/IsSupportedChipGroup.astro";
import Prerequisites from "@mdx/Prerequisites.astro";

<IsSupportedChipGroup chips={{PostgreSQL: true, MySQL: true, SQLite: true, MSSQL: true, Cockroach: true}}/>

<Prerequisites>
- Get started with [PostgreSQL](/docs/get-started-postgresql), [MySQL](/docs/mysql/get-started-mysql), [SQLite](/docs/sqlite/get-started-sqlite), [MSSQL](/docs/mssql/get-started-mssql) and [Cockroach](/docs/cockroach/get-started-cockroach)
- [Update statement](/docs/update)
- [Filters](/docs/operators) and [sql operator](/docs/sql)
</Prerequisites>

To increment a column value you can use `update().set()` method like below:

<Section>
```ts copy {8}
import { eq, sql } from 'drizzle-orm';

const db = drizzle(...)
  
await db
  .update(table)
  .set({
    counter: sql`${table.counter} + 1`,
  })
  .where(eq(table.id, 1));
```

```sql
update "table" set "counter" = "counter" + 1 where "id" = 1;
```
</Section>

Drizzle has simple and flexible API, which lets you easily create custom solutions. This is how you do custom increment function:

```ts copy {4,10,11}
import { AnyColumn } from 'drizzle-orm';

const increment = (column: AnyColumn, value = 1) => {
  return sql`${column} + ${value}`;
};

await db
  .update(table)
  .set({
    counter1: increment(table.counter1),
    counter2: increment(table.counter2, 10),
  })
  .where(eq(table.id, 1));
```


Source: https://orm.drizzle.team/docs/guides/limit-offset-pagination


import CodeTabs from '@mdx/CodeTabs.astro';
import CodeTab from '@mdx/CodeTab.astro';
import Section from "@mdx/Section.astro";
import Prerequisites from "@mdx/Prerequisites.astro";
import IsSupportedChipGroup from "@mdx/IsSupportedChipGroup.astro";

<IsSupportedChipGroup chips={{PostgreSQL: true, MySQL: true, SQLite: true, MSSQL: true, Cockroach: true}}/>

<Prerequisites>
- Get started with [PostgreSQL](/docs/get-started-postgresql), [MySQL](/docs/mysql/get-started-mysql), [SQLite](/docs/sqlite/get-started-sqlite), [MSSQL](/docs/mssql/get-started-mssql) and [Cockroach](/docs/cockroach/get-started-cockroach)
- [Select statement](/docs/select) with [order by clause](/docs/select#order-by) and [limit & offset clauses](/docs/select#limit--offset)
- [Relational queries](/docs/rqb) with [order by clause](/docs/rqb#order-by) and [limit & offset clauses](/docs/rqb#limit--offset)
- [Dynamic query building](/docs/dynamic-query-building)
</Prerequisites>

This guide demonstrates how to implement `limit/offset` pagination in Drizzle:

### PostgreSQL, MySQL, SQLite and Cockroach

To implement a PostgreSQL, MySQL, SQLite and Cockroach SQL Limit/Offset pagination (skip to [MSSQL](/docs/guides/limit-offset-pagination#mssql)) with Drizzle you can use following example:

<CodeTabs items={["index.ts", "schema.ts"]}>
  <CodeTab>
    ```ts copy {9,10,11}
    import { asc } from 'drizzle-orm';
    import { users } from './schema';

    const db = drizzle(...);

    await db
      .select()
      .from(users)
      .orderBy(asc(users.id)) // order by is mandatory
      .limit(4) // the number of rows to return
      .offset(4); // the number of rows to skip
    ```

    ```sql
    select * from users order by id asc limit 4 offset 4;
    ```

    ```ts
    // 5-8 rows returned
    [
      {
        id: 5,
        firstName: 'Beth',
        lastName: 'Davis',
        createdAt: 2024-03-11T20:51:46.787Z
      },
      {
        id: 6,
        firstName: 'Charlie',
        lastName: 'Miller',
        createdAt: 2024-03-11T21:15:46.787Z
      },
      {
        id: 7,
        firstName: 'Clara',
        lastName: 'Wilson',
        createdAt: 2024-03-11T21:33:46.787Z
      },
      {
        id: 8,
        firstName: 'David',
        lastName: 'Moore',
        createdAt: 2024-03-11T21:45:46.787Z
      }
    ]
    ```
  </CodeTab>
  <CodeTab>
    ```ts copy
    import { pgTable, serial, text, timestamp } from 'drizzle-orm/pg-core';

    export const users = pgTable('users', {
      id: serial('id').primaryKey(),
      firstName: text('first_name').notNull(),
      lastName: text('last_name').notNull(),
      createdAt: timestamp('created_at').notNull().defaultNow(),
    });
    ```

    ```plaintext
    +----+------------+-----------+----------------------------+
    | id | first_name | last_name |         created_at         |
    +----+------------+-----------+----------------------------+
    |  1 | Alice      | Johnson   | 2024-03-08 12:23:55.251797 |
    +----+------------+-----------+----------------------------+
    |  2 | Alex       | Smith     | 2024-03-08 12:25:55.182    |
    +----+------------+-----------+----------------------------+
    |  3 | Aaron      | Williams  | 2024-03-08 12:28:55.182    |
    +----+------------+-----------+----------------------------+
    |  4 | Brian      | Brown     | 2024-03-08 12:34:55.182    |
    +----+------------+-----------+----------------------------+
    |  5 | Beth       | Davis     | 2024-03-08 12:40:55.182    |
    +----+------------+-----------+----------------------------+
    |  6 | Charlie    | Miller    | 2024-03-08 13:04:55.182    |
    +----+------------+-----------+----------------------------+
    |  7 | Clara      | Wilson    | 2024-03-08 13:22:55.182    |
    +----+------------+-----------+----------------------------+
    |  8 | David      | Moore     | 2024-03-08 13:34:55.182    |
    +----+------------+-----------+----------------------------+
    ```
  </CodeTab>
</CodeTabs>

Limit is the number of rows to return `(page size)` and offset is the number of rows to skip `((page number - 1) * page size)`. 
For consistent pagination, ensure ordering by a unique column. Otherwise, the results can be inconsistent.

If you need to order by a non-unique column, you should also append a unique column to the ordering.

This is how you can implement `limit/offset` pagination with 2 columns:

<Section>
```ts copy {5}
const getUsers = async (page = 1, pageSize = 3) => {
  await db
    .select()
    .from(users)
    .orderBy(asc(users.firstName), asc(users.id)) // order by first_name (non-unique), id (pk)
    .limit(pageSize) 
    .offset((page - 1) * pageSize);
}

await getUsers();
```
</Section>

Drizzle has useful relational queries API, that lets you easily implement `limit/offset` pagination:

<Section>
```ts copy {7,8,9}
import * as schema from './db/schema';

const db = drizzle({ schema });

const getUsers = async (page = 1, pageSize = 3) => {
  await db.query.users.findMany({
    orderBy: (users, { asc }) => asc(users.id),
    limit: pageSize,
    offset: (page - 1) * pageSize,
  });
};

await getUsers();
```
</Section>

Drizzle has simple and flexible API, which lets you easily create custom solutions. This is how you can create custom function for pagination using `.$dynamic()` function:

<Section>
```ts copy {11,12,13,16}
import { SQL, asc } from 'drizzle-orm';
import { PgColumn, PgSelect } from 'drizzle-orm/pg-core';

function withPagination<T extends PgSelect>(
  qb: T,
  orderByColumn: PgColumn | SQL | SQL.Aliased,
  page = 1,
  pageSize = 3,
) {
  return qb
    .orderBy(orderByColumn)
    .limit(pageSize)
    .offset((page - 1) * pageSize);
}

const query = db.select().from(users); // query that you want to execute with pagination

await withPagination(query.$dynamic(), asc(users.id));
```

</Section>

You can improve performance of `limit/offset` pagination by using `deferred join` technique. This method performs the pagination on a subset of the data instead of the entire table.

To implement it you can do like this:

```ts copy {10}
const getUsers = async (page = 1, pageSize = 10) => {
   const sq = db
    .select({ id: users.id })
    .from(users)
    .orderBy(users.id)
    .limit(pageSize)
    .offset((page - 1) * pageSize)
    .as('subquery');

   await db.select().from(users).innerJoin(sq, eq(users.id, sq.id)).orderBy(users.id);
};
```

**Benefits** of `limit/offset` pagination: it's simple to implement and pages are easily reachable, which means that you can navigate to any page without having to save the state of the previous pages.

**Drawbacks** of `limit/offset` pagination: degradation in query performance with increasing offset because database has to scan all rows before the offset to skip them, and inconsistency due to data shifts, which can lead to the same row being returned on different pages or rows being skipped.

This is how it works:

<Section>
```ts copy
const getUsers = async (page = 1, pageSize = 3) => {
  await db
    .select()
    .from(users)
    .orderBy(asc(users.id))
    .limit(pageSize)
    .offset((page - 1) * pageSize);
};

// user is browsing the first page
await getUsers();
```

```ts
// results for the first page
[
  {
    id: 1,
    firstName: 'Alice',
    lastName: 'Johnson',
    createdAt: 2024-03-10T17:17:06.148Z
  },
  {
    id: 2,
    firstName: 'Alex',
    lastName: 'Smith',
    createdAt: 2024-03-10T17:19:06.147Z
  },
  {
    id: 3,
    firstName: 'Aaron',
    lastName: 'Williams',
    createdAt: 2024-03-10T17:22:06.147Z
  }
]
```

```ts
// while user is browsing the first page, a row with id 2 is deleted
await db.delete(users).where(eq(users.id, 2));

// user navigates to the second page
await getUsers(2);
```

```ts
// second page, row with id 3 was skipped
[
  {
    id: 5,
    firstName: 'Beth',
    lastName: 'Davis',
    createdAt: 2024-03-10T17:34:06.147Z
  },
  {
    id: 6,
    firstName: 'Charlie',
    lastName: 'Miller',
    createdAt: 2024-03-10T17:58:06.147Z
  },
  {
    id: 7,
    firstName: 'Clara',
    lastName: 'Wilson',
    createdAt: 2024-03-10T18:16:06.147Z
  }
]
```
</Section>

So, if your database experiences frequently insert and delete operations in real time or you need high performance to paginate large tables, you should consider using [cursor-based](/docs/guides/cursor-based-pagination) pagination instead.

To learn more about `deferred join` technique you should follow these guides: [Planetscale Pagination Guide](https://planetscale.com/blog/mysql-pagination) and [Efficient Pagination Guide by Aaron Francis](https://aaronfrancis.com/2022/efficient-pagination-using-deferred-joins).

{/*TODO finish this*/}
### MSSQL

To implement an MSSQL Limit/Offset pagination with Drizzle you can use following example:

<CodeTabs items={["index.ts", "schema.ts"]}>
  <CodeTab>
    ```ts copy {9,10,11}
    import { asc } from 'drizzle-orm';
    import { users } from './schema';

    const db = drizzle(...);

    await db
	  .select()
	  .from(users)
	  .orderBy(asc(users.id)) // order by is mandatory
	  .offset(4) // the number of rows to skip
	  .fetch(4) // the number of rows to fetch
    ```

    ```sql
    select * from [users] order by [id] asc offset 5 rows fetch next 10 rows only;
    ```

    ```ts
    // 5-8 rows returned
    [
      {
        id: 5,
        firstName: 'Beth',
        lastName: 'Davis',
        createdAt: 2024-03-11T20:51:46.787Z
      },
      {
        id: 6,
        firstName: 'Charlie',
        lastName: 'Miller',
        createdAt: 2024-03-11T21:15:46.787Z
      },
      {
        id: 7,
        firstName: 'Clara',
        lastName: 'Wilson',
        createdAt: 2024-03-11T21:33:46.787Z
      },
      {
        id: 8,
        firstName: 'David',
        lastName: 'Moore',
        createdAt: 2024-03-11T21:45:46.787Z
      }
    ]
    ```
  </CodeTab>
  <CodeTab>
    ```ts copy
    import { datetime2, int, mssqlTable, text } from "drizzle-orm/mssql-core";

    export const users = mssqlTable("users", {
      id: int("id").primaryKey(),
      firstName: text("first_name").notNull(),
      lastName: text("last_name").notNull(),
      createdAt: datetime2("created_at", { mode: "date" }).notNull().defaultGetDate(),
    });
    ```

    ```plaintext
    +----+------------+-----------+----------------------------+
    | id | first_name | last_name |         created_at         |
    +----+------------+-----------+----------------------------+
    |  1 | Alice      | Johnson   | 2024-03-08 12:23:55.251797 |
    +----+------------+-----------+----------------------------+
    |  2 | Alex       | Smith     | 2024-03-08 12:25:55.182    |
    +----+------------+-----------+----------------------------+
    |  3 | Aaron      | Williams  | 2024-03-08 12:28:55.182    |
    +----+------------+-----------+----------------------------+
    |  4 | Brian      | Brown     | 2024-03-08 12:34:55.182    |
    +----+------------+-----------+----------------------------+
    |  5 | Beth       | Davis     | 2024-03-08 12:40:55.182    |
    +----+------------+-----------+----------------------------+
    |  6 | Charlie    | Miller    | 2024-03-08 13:04:55.182    |
    +----+------------+-----------+----------------------------+
    |  7 | Clara      | Wilson    | 2024-03-08 13:22:55.182    |
    +----+------------+-----------+----------------------------+
    |  8 | David      | Moore     | 2024-03-08 13:34:55.182    |
    +----+------------+-----------+----------------------------+
    ```
  </CodeTab>
</CodeTabs>


Source: https://orm.drizzle.team/docs/guides/mysql-local-setup


import Section from "@mdx/Section.astro";
import Prerequisites from "@mdx/Prerequisites.astro";
import CodeTabs from '@mdx/CodeTabs.astro';
import CodeTab from '@mdx/CodeTab.astro';
import Steps from '@mdx/Steps.astro';

<Prerequisites>
- Install latest [Docker Desktop](https://www.docker.com/products/docker-desktop/). Follow the instructions for your operating system.
</Prerequisites>

<Steps>

#### Pull the MySQL image

Pull the latest MySQL image from Docker Hub. In your terminal, run `docker pull mysql` to pull the latest MySQL version from Docker Hub:

```bash copy
docker pull mysql
```

Alternatively, you can pull preferred version with a specific tag:

```bash copy
docker pull mysql:8.2
```

When MySQL image is downloaded, you can check it in `Images` tab in Docker Desktop or by running `docker images`:

<Section>
```bash copy
docker images
```

```plaintext
REPOSITORY   TAG       IMAGE ID       CREATED        SIZE
mysql        latest    4e8a34aea708   2 months ago   609MB
```
</Section>

#### Start a MySQL instance

To start a new MySQL container, run the following command:

```bash copy
docker run --name drizzle-mysql -e MYSQL_ROOT_PASSWORD=mypassword -d -p 3306:3306 mysql
```

1. The `--name` option assigns the container the name `drizzle-mysql`.
2. The `-e MYSQL_ROOT_PASSWORD=` option sets the `MYSQL_ROOT_PASSWORD` environment variable with the specified value. This is password for the root user.
3. The `-d` flag runs the container in detached mode (in the background).
4. The `-p` option maps port `3306` on the container to port `3306` on your host machine, allowing MySQL to be accessed from your host system through this port.
5. The `mysql` argument specifies the image to use for the container. You can also specify other versions like `mysql:8.2`.

You can also specify other parameters like:

1. `-e MYSQL_DATABASE=` to create a new database when the container is created. Default is `mysql`.
2. `-e MYSQL_USER=` and `-e MYSQL_PASSWORD=` to create a new user with a password when the container is created. But you still need to specify `MYSQL_ROOT_PASSWORD` for `root` user.

To check if the container is running, check `Containers` tab in Docker Desktop or use the `docker ps` command:

```plaintext
CONTAINER ID   IMAGE         COMMAND                  CREATED          STATUS          PORTS                               NAMES
19506a8dc12b   mysql         "docker-entrypoint.s…"   4 seconds ago    Up 3 seconds    33060/tcp, 0.0.0.0:3306->3306/tcp   drizzle-mysql
```

#### Configure database url

To connect to the MySQL database, you need to provide the database URL. The URL format is:

```plaintext
mysql://<user>:<password>@<host>:<port>/<database>
```

You should replace placeholders with your actual values. For example, for created container the url will be:

```plaintext
mysql://root:mypassword@localhost:3306/mysql
```

Now you can connect to the database using the URL in your application.
</Steps>


Source: https://orm.drizzle.team/docs/guides/point-datatype-psql


import Section from "@mdx/Section.astro";
import Prerequisites from "@mdx/Prerequisites.astro";
import CodeTabs from '@mdx/CodeTabs.astro';
import CodeTab from '@mdx/CodeTab.astro';
import Callout from '@mdx/Callout.astro';

<Prerequisites>
- Get started with [PostgreSQL](/docs/get-started-postgresql)
- [Point datatype](/docs/column-types#point)
- [Filtering in select statement](/docs/select#filtering)
- [sql operator](/docs/sql)
</Prerequisites>

PostgreSQL has a special datatype to store geometric data called `point`. It is used to represent a point in a two-dimensional space. The point datatype is represented as a pair of `(x, y)` coordinates.
The point expects to receive longitude first, followed by latitude.

<Section>
```ts copy {6}
import { sql } from 'drizzle-orm';

const db = drizzle(...);

await db.execute(
  sql`select point(-90.9, 18.7)`,
);
```

```json
[ 
  { 
    point: '(-90.9,18.7)' 
  }
]
```
</Section>

This is how you can create table with `point` datatype in Drizzle:

```ts {6}
import { pgTable, point, serial, text } from 'drizzle-orm/pg-core';

export const stores = pgTable('stores', {
  id: serial('id').primaryKey(),
  name: text('name').notNull(),
  location: point('location', { mode: 'xy' }).notNull(),
});
```

This is how you can insert point data into the table in Drizzle:

```ts {4, 10, 16}
// mode: 'xy'
await db.insert(stores).values({
  name: 'Test',
  location: { x: -90.9, y: 18.7 },
});

// mode: 'tuple'
await db.insert(stores).values({
  name: 'Test',
  location: [-90.9, 18.7],
});

// sql raw
await db.insert(stores).values({
  name: 'Test',
  location: sql`point(-90.9, 18.7)`,
});
```

To compute the distance between the objects you can use `<->` operator. This is how you can query for the nearest location by coordinates in Drizzle:

<Callout type='warning'>
`getColumns` available starting from `drizzle-orm@1.0.0-beta.2`(read more [here](/docs/upgrade-v1))

If you are on pre-1 version(like `0.45.1`) then use `getTableColumns`
</Callout>

<Section>
```ts {9, 14, 17}
import { getColumns, sql } from 'drizzle-orm';
import { stores } from './schema';

const point = {
  x: -73.935_242,
  y: 40.730_61,
};

const sqlDistance = sql`location <-> point(${point.x}, ${point.y})`;

await db
  .select({
    ...getColumns(stores),
    distance: sql`round((${sqlDistance})::numeric, 2)`,
  })
  .from(stores)
  .orderBy(sqlDistance)
  .limit(1);
```

```sql
select *, round((location <-> point(-73.935242, 40.73061))::numeric, 2)
from stores order by location <-> point(-73.935242, 40.73061)
limit 1;
```
</Section>

To filter rows to include only those where a `point` type `location` falls within a specified rectangular boundary defined by two diagonal points you can user `<@` operator. It checks if the first object is contained in or on the second object:

<Section>
```ts {12}
const point = {
  x1: -88,
  x2: -73,
  y1: 40,
  y2: 43,
};

await db
  .select()
  .from(stores)
  .where(
    sql`${stores.location} <@ box(point(${point.x1}, ${point.y1}), point(${point.x2}, ${point.y2}))`
  );
```

```sql
select * from stores where location <@ box(point(-88, 40), point(-73, 43));
```
</Section>





Source: https://orm.drizzle.team/docs/guides/postgis-geometry-point


import Section from "@mdx/Section.astro";
import Prerequisites from "@mdx/Prerequisites.astro";
import CodeTabs from '@mdx/CodeTabs.astro';
import Callout from "@mdx/Callout.astro";
import CodeTab from '@mdx/CodeTab.astro';

<Prerequisites>
- Get started with [PostgreSQL](/docs/get-started-postgresql)
- [Postgis extension](/docs/extensions#postgis)
- [Indexes](/docs/indexes-constraints#indexes)
- [Filtering in select statement](/docs/select#filtering)
- [sql operator](/docs/sql)
</Prerequisites>

`PostGIS` extends the capabilities of the PostgreSQL relational database by adding support for storing, indexing, and querying geospatial data. 

As for now, Drizzle doesn't create extension automatically, so you need to create it manually. Create an empty migration file and add SQL query:

<Section>
```bash
npx drizzle-kit generate --custom
```

```sql
CREATE EXTENSION postgis;
```
</Section>

This is how you can create table with `geometry` datatype and spatial index in Drizzle:

<CodeTabs items={["schema.ts", "migration.sql"]}>
  <CodeTab>
  ```ts copy {8, 11}
  import { geometry, index, pgTable, serial, text } from 'drizzle-orm/pg-core';

  export const stores = pgTable(
    'stores',
    {
      id: serial('id').primaryKey(),
      name: text('name').notNull(),
      location: geometry('location', { type: 'point', mode: 'xy', srid: 4326 }).notNull(),
    },
    (t) => [
      index('spatial_index').using('gist', t.location),
    ]
  );
  ```
  </CodeTab>
  ```sql
  CREATE TABLE IF NOT EXISTS "stores" (
	  "id" serial PRIMARY KEY NOT NULL,
	  "name" text NOT NULL,
	  "location" geometry(point) NOT NULL
  );
  --> statement-breakpoint
  CREATE INDEX IF NOT EXISTS "spatial_index" ON "stores" USING gist ("location");
  ```
</CodeTabs>
 
This is how you can insert `geometry` data into the table in Drizzle. `ST_MakePoint()` in PostGIS creates a geometric object of type `point` using the specified coordinates.
`ST_SetSRID()` sets the `SRID` (unique identifier associated with a specific coordinate system, tolerance, and resolution) on a geometry to a particular integer value:

```ts {4, 10, 16}
// mode: 'xy'
await db.insert(stores).values({
  name: 'Test',
  location: { x: -90.9, y: 18.7 },
});

// mode: 'tuple'
await db.insert(stores).values({
  name: 'Test',
  location: [-90.9, 18.7],
});

// sql raw
await db.insert(stores).values({
  name: 'Test',
  location: sql`ST_SetSRID(ST_MakePoint(-90.9, 18.7), 4326)`,
});
```

To compute the distance between the objects you can use `<->` operator and `ST_Distance()` function, which for `geometry types` returns the minimum planar distance between two geometries. This is how you can query for the nearest location by coordinates in Drizzle with PostGIS:

<Callout type='warning'>
`getColumns` available starting from `drizzle-orm@1.0.0-beta.2`(read more [here](/docs/upgrade-v1))

If you are on pre-1 version(like `0.45.1`) then use `getTableColumns`
</Callout>

<Section>
```ts copy {9, 14, 17}
import { getColumns, sql } from 'drizzle-orm';
import { stores } from './schema';

const point = {
  x: -73.935_242,
  y: 40.730_61,
};

const sqlPoint = sql`ST_SetSRID(ST_MakePoint(${point.x}, ${point.y}), 4326)`;

await db
  .select({
    ...getColumns(stores),
    distance: sql`ST_Distance(${stores.location}, ${sqlPoint})`,
  })
  .from(stores)
  .orderBy(sql`${stores.location} <-> ${sqlPoint}`)
  .limit(1);
```

```sql
select *, ST_Distance(location, ST_SetSRID(ST_MakePoint(-73.935_242, 40.730_61), 4326))
from stores order by location <-> ST_SetSRID(ST_MakePoint(-73.935_242, 40.730_61), 4326)
limit 1;
```
</Section>

To filter stores located within a specified rectangular area, you can use `ST_MakeEnvelope()` and `ST_Within()` functions. `ST_MakeEnvelope()` creates a rectangular Polygon from the minimum and maximum values for X and Y. `ST_Within()` Returns TRUE if geometry A is within geometry B.

<Section>
```ts copy {13}
const point = {
  x1: -88,
  x2: -73,
  y1: 40,
  y2: 43,
};

await db
  .select()
  .from(stores)
  .where(
    sql`ST_Within(
      ${stores.location}, ST_MakeEnvelope(${point.x1}, ${point.y1}, ${point.x2}, ${point.y2}, 4326)
    )`,
  );
```

```sql
select * from stores where ST_Within(location, ST_MakeEnvelope(-88, 40, -73, 43, 4326));
```
</Section>


Source: https://orm.drizzle.team/docs/guides/postgresql-full-text-search


import Section from "@mdx/Section.astro";
import Prerequisites from "@mdx/Prerequisites.astro";
import CodeTabs from '@mdx/CodeTabs.astro';
import CodeTab from '@mdx/CodeTab.astro';
import Callout from '@mdx/Callout.astro';

<Prerequisites>
- Get started with [PostgreSQL](/docs/get-started-postgresql)
- [Select statement](/docs/select)
- [Indexes](/docs/indexes-constraints#indexes)
- [sql operator](/docs/sql)
- You should have `drizzle-orm@0.31.0` and `drizzle-kit@0.22.0` or higher.  
</Prerequisites>

This guide demonstrates how to implement full-text search in PostgreSQL with Drizzle ORM. Full-text search is a technique used to search for text within a document or a set of documents. A document is the unit of searching in a full text search system. PostgreSQL provides a set of functions to work with full-text search, such as `to_tsvector` and `to_tsquery`:

The `to_tsvector` function parses a textual document into tokens, reduces the tokens to lexemes, and returns a `tsvector` which lists the lexemes together with their positions in the document:

<Section>
```ts copy {6}
import { sql } from 'drizzle-orm';

const db = drizzle(...);

await db.execute(
  sql`select to_tsvector('english', 'Guide to PostgreSQL full-text search with Drizzle ORM')`,
);
```

```json
[
  {
    to_tsvector: "'drizzl':9 'full':5 'full-text':4
    'guid':1 'orm':10 'postgresql':3 'search':7 'text':6"
  }
]
```
</Section>

The `to_tsquery` function converts a keyword to normalized tokens and returns a `tsquery` that matches the lexemes in a `tsvector`. The `@@` operator is used for direct matches:

<Section>
```ts copy {2, 3}
await db.execute(
  sql`select to_tsvector('english', 'Guide to PostgreSQL full-text search with Drizzle ORM')
    @@ to_tsquery('english', 'Drizzle') as match`,
);
```

```json
[ { match: true } ]
```
</Section>

As for now, Drizzle doesn't support `tsvector` type natively, so you need to convert your data in the `text` column on the fly. To enhance the performance, you can create a `GIN` index on your column like this:

<CodeTabs items={["schema.ts", "migration.sql", "db_data"]}>
  <CodeTab>
  ```ts copy {10, 11}
  import { index, pgTable, serial, text } from 'drizzle-orm/pg-core';

  export const posts = pgTable(
    'posts',
    {
      id: serial('id').primaryKey(),
      title: text('title').notNull(),
    },
    (table) => [
      index('title_search_index').using('gin', sql`to_tsvector('english', ${table.title})`),
    ]
  );
  ```
  </CodeTab>
  <CodeTab>
  ```sql
  CREATE TABLE IF NOT EXISTS "posts" (
          "id" serial PRIMARY KEY NOT NULL,
          "title" text NOT NULL
  );

  CREATE INDEX IF NOT EXISTS "title_search_index" ON "posts"
    USING gin (to_tsvector('english', "title"));
  ```
  </CodeTab>
  ```json
  [
    { id: 1, title: 'Planning Your First Trip to Europe' },
    { id: 2, title: "Cultural Insights: Exploring Asia's Heritage" },
    { id: 3, title: 'Top 5 Destinations for a Family Trip' },
    { id: 4, title: 'Essential Hiking Gear for Mountain Enthusiasts' },
    { id: 5, title: 'Trip Planning: Choosing Your Next Destination' },
    { id: 6, title: 'Discovering Hidden Culinary Gems in Italy' },
    { id: 7, title: 'The Ultimate Road Trip Guide for Explorers' },
  ];
  ```
</CodeTabs>

To implement full-text search in PostgreSQL with Drizzle ORM, you can use the `to_tsvector` and `to_tsquery` functions with `sql` operator:

<Section>
```ts copy {9}
import { sql } from 'drizzle-orm';
import { posts } from './schema';

const title = 'trip';

await db
  .select()
  .from(posts)
  .where(sql`to_tsvector('english', ${posts.title}) @@ to_tsquery('english', ${title})`);
```

```json
[
  { id: 1, title: 'Planning Your First Trip to Europe' },
  { id: 3, title: 'Top 5 Destinations for a Family Trip' },
  { id: 5, title: 'Trip Planning: Choosing Your Next Destination' },
  { id: 7, title: 'The Ultimate Road Trip Guide for Explorers' }
]
```
</Section>

To match by any of the keywords, you can use the `|` operator:

<Section>
```ts copy {6}
const title = 'Europe | Asia';

await db
  .select()
  .from(posts)
  .where(sql`to_tsvector('english', ${posts.title}) @@ to_tsquery('english', ${title})`);
```

```json
[
  { id: 1, title: 'Planning Your First Trip to Europe' },
  { id: 2, title: "Cultural Insights: Exploring Asia's Heritage" }
]
```
</Section>

To match multiple keywords, you can use the `plainto_tsquery` function:

<Section>
```ts copy {7}
// 'discover & Italy'
const title = 'discover Italy';

await db
  .select()
  .from(posts)
  .where(sql`to_tsvector('english', ${posts.title}) @@ plainto_tsquery('english', ${title})`);
```

```sql
select * from posts
  where to_tsvector('english', title) @@ plainto_tsquery('english', 'discover Italy');
```

```json
[ { id: 6, title: 'Discovering Hidden Culinary Gems in Italy' } ]
```
</Section>

To match a phrase, you can use the `phraseto_tsquery` function:

<Section>
```ts copy {8}
// if you query by "trip family", it will not return any result
// 'family <-> trip'
const title = 'family trip';

await db
  .select()
  .from(posts)
  .where(sql`to_tsvector('english', ${posts.title}) @@ phraseto_tsquery('english', ${title})`);
```

```sql
select * from posts
  where to_tsvector('english', title) @@ phraseto_tsquery('english', 'family trip');
```

```json
[ { id: 3, title: 'Top 5 Destinations for a Family Trip' } ]
```
</Section>

You can also use `websearch_to_tsquery` function which is a simplified version of `to_tsquery` with an alternative syntax, similar to the one used by web search engines:

<Section>
```ts copy {7}
// 'family | first & trip & europ | asia'
const title = 'family or first trip Europe or Asia';

await db
  .select()
  .from(posts)
  .where(sql`to_tsvector('english', ${posts.title}) @@ websearch_to_tsquery('english', ${title})`);
```

```sql
select * from posts
  where to_tsvector('english', title)
  @@ websearch_to_tsquery('english', 'family or first trip Europe or Asia');
```

```json
[
  { id: 1, title: 'Planning Your First Trip to Europe' },
  { id: 2, title: "Cultural Insights: Exploring Asia's Heritage" },
  { id: 3, title: 'Top 5 Destinations for a Family Trip' }
]
```
</Section>

To implement full-text search on multiple columns, you can create index on multiple columns and concatenate the columns with `to_tsvector` function:

<CodeTabs items={["schema.ts", "migration.sql", "db_data"]}>
  <CodeTab>
  ```ts copy {12-17}
  import { sql } from 'drizzle-orm';
  import { index, pgTable, serial, text } from 'drizzle-orm/pg-core';

  export const posts = pgTable(
    'posts',
    {
      id: serial('id').primaryKey(),
      title: text('title').notNull(),
      description: text('description').notNull(),
    },
    (table) => [
      index('search_index').using(
        'gin',
        sql`(
            setweight(to_tsvector('english', ${table.title}), 'A') ||
            setweight(to_tsvector('english', ${table.description}), 'B')
        )`,
      ),
    ],
  );
  ```
  </CodeTab>
  <CodeTab>
  ```sql
  CREATE TABLE IF NOT EXISTS "posts" (
        "id" serial PRIMARY KEY NOT NULL,
        "title" text NOT NULL,
        "description" text NOT NULL
  );

  CREATE INDEX IF NOT EXISTS "search_index" ON "posts"
    USING gin ((setweight(to_tsvector('english', "title"), 'A') ||
    setweight(to_tsvector('english', "description"), 'B')));
  ```
  </CodeTab>
  ```json
  [
    {
      id: 1,
      title: 'Planning Your First Trip to Europe',
      description:
        'Get essential tips on budgeting, sightseeing, and cultural etiquette for your inaugural European adventure.',
    },
    {
      id: 2,
      title: "Cultural Insights: Exploring Asia's Heritage",
      description:
        'Dive deep into the rich history and traditions of Asia through immersive experiences and local interactions.',
    },
    {
      id: 3,
      title: 'Top 5 Destinations for a Family Trip',
      description:
        'Discover family-friendly destinations that offer fun, education, and relaxation for all ages.',
    },
    {
      id: 4,
      title: 'Essential Hiking Gear for Mountain Enthusiasts',
      description:
        'Equip yourself with the latest and most reliable gear for your next mountain hiking expedition.',
    },
    {
      id: 5,
      title: 'Trip Planning: Choosing Your Next Destination',
      description:
        'Learn how to select destinations that align with your travel goals, whether for leisure, adventure, or cultural exploration.',
    },
    {
      id: 6,
      title: 'Discovering Hidden Culinary Gems in Italy',
      description:
        "Unearth Italy's lesser-known eateries and food markets that offer authentic and traditional flavors.",
    },
    {
      id: 7,
      title: 'The Ultimate Road Trip Guide for Explorers',
      description:
        'Plan your next great road trip with tips on route planning, packing, and discovering off-the-beaten-path attractions.',
    },
  ];
  ```
</CodeTabs>

The `setweight` function is used to label the entries of a tsvector with a given weight, where a weight is one of the letters A, B, C, or D. This is typically used to mark entries coming from different parts of a document, such as title versus body.

This is how you can query on multiple columns:

<Section>
```ts copy {5-7}
const title = 'plan';

await db.select().from(posts)
  .where(sql`(
      setweight(to_tsvector('english', ${posts.title}), 'A') ||
      setweight(to_tsvector('english', ${posts.description}), 'B'))
      @@ to_tsquery('english', ${title}
    )`
  );
```

```json
[
  {
    id: 1,
    title: 'Planning Your First Trip to Europe',
    description: 'Get essential tips on budgeting, sightseeing, and cultural etiquette for your inaugural European adventure.'
  },
  {
    id: 5,
    title: 'Trip Planning: Choosing Your Next Destination',
    description: 'Learn how to select destinations that align with your travel goals, whether for leisure, adventure, or cultural exploration.'
  },
  {
    id: 7,
    title: 'The Ultimate Road Trip Guide for Explorers',
    description: 'Plan your next great road trip with tips on route planning, packing, and discovering off-the-beaten-path attractions.'
  }
]
```
</Section>

To rank the search results, you can use the `ts_rank` or `ts_rank_cd` functions and `orderBy` method:

<Callout type='warning'>
`getColumns` available starting from `drizzle-orm@1.0.0-beta.2`(read more [here](/docs/upgrade-v1))

If you are on pre-1 version(like `0.45.1`) then use `getTableColumns`
</Callout>

<Section>
```ts copy {6,7,12,13,18-20}
import { desc, getColumns, sql } from 'drizzle-orm';

const search = 'culture | Europe | Italy | adventure';

const matchQuery = sql`(
  setweight(to_tsvector('english', ${posts.title}), 'A') ||
  setweight(to_tsvector('english', ${posts.description}), 'B')), to_tsquery('english', ${search})`;

await db
  .select({
    ...getColumns(posts),
    rank: sql`ts_rank(${matchQuery})`,
    rankCd: sql`ts_rank_cd(${matchQuery})`,
  })
  .from(posts)
  .where(
    sql`(
      setweight(to_tsvector('english', ${posts.title}), 'A') ||
      setweight(to_tsvector('english', ${posts.description}), 'B')
      ) @@ to_tsquery('english', ${search})`,
  )
  .orderBy((t) => desc(t.rank));
```

```json
[
  {
    id: 1,
    title: 'Planning Your First Trip to Europe',
    description: 'Get essential tips on budgeting, sightseeing, and cultural etiquette for your inaugural European adventure.',
    rank: 0.2735672,
    rankCd: 1.8
  },
  {
    id: 6,
    title: 'Discovering Hidden Culinary Gems in Italy',
    description: "Unearth Italy's lesser-known eateries and food markets that offer authentic and traditional flavors.",
    rank: 0.16717994,
    rankCd: 1.4
  },
  {
    id: 2,
    title: "Cultural Insights: Exploring Asia's Heritage",
    description: 'Dive deep into the rich history and traditions of Asia through immersive experiences and local interactions.',
    rank: 0.15198177,
    rankCd: 1
  },
  {
    id: 5,
    title: 'Trip Planning: Choosing Your Next Destination',
    description: 'Learn how to select destinations that align with your travel goals, whether for leisure, adventure, or cultural exploration.',
    rank: 0.12158542,
    rankCd: 0.8
  }
]
```
</Section>

The `ts_rank` function focuses on the frequency of query terms throughout the document. The `ts_rank_cd` function focuses on the proximity of query terms within the document.


Source: https://orm.drizzle.team/docs/guides/postgresql-local-setup


import Section from "@mdx/Section.astro";
import Prerequisites from "@mdx/Prerequisites.astro";
import CodeTabs from '@mdx/CodeTabs.astro';
import CodeTab from '@mdx/CodeTab.astro';
import Steps from '@mdx/Steps.astro';

<Prerequisites>
- Install latest [Docker Desktop](https://www.docker.com/products/docker-desktop/). Follow the instructions for your operating system.
</Prerequisites>

<Steps>

#### Pull the PostgreSQL image

Pull the latest PostgreSQL image from Docker Hub. In your terminal, run `docker pull postgres` to pull the latest Postgres version from Docker Hub:

```bash copy
docker pull postgres
```

Alternatively, you can pull preferred version with a specific tag:

```bash copy
docker pull postgres:15
```

When postgres image is downloaded, you can check it in `Images` tab in Docker Desktop or by running `docker images`:

<Section>
```bash copy
docker images
```

```plaintext
REPOSITORY   TAG       IMAGE ID       CREATED         SIZE
postgres     latest    75282fa229a1   6 weeks ago     453MB
```
</Section>

#### Start a Postgres instance

To start a new PostgreSQL container, run the following command:

```bash copy
docker run --name drizzle-postgres -e POSTGRES_PASSWORD=mypassword -d -p 5432:5432 postgres
```

1. The `--name` option assigns the container the name `drizzle-postgres`.
2. The `-e POSTGRES_PASSWORD=` option sets the `POSTGRES_PASSWORD` environment variable with the specified value.
3. The `-d` flag runs the container in detached mode (in the background).
4. The `-p` option maps port `5432` on the container to port `5432` on your host machine, allowing PostgreSQL to be accessed from your host system through this port.
5. The `postgres` argument specifies the image to use for the container. You can also specify other versions like `postgres:15`.

You can also specify other parameters like:

1. The `-e POSTGRES_USER=` option sets the `POSTGRES_USER` environment variable with the specified value. Postgres uses the default user when this is empty. Most of the time, it is `postgres` and you can check it in the container logs in Docker Desktop or by running `docker logs <container_name>`.
2. The `-e POSTGRES_DB=` option sets the `POSTGRES_DB` environment variable with the specified value. Defaults to the `POSTGRES_USER` value when is empty.

To check if the container is running, check `Containers` tab in Docker Desktop or use the `docker ps` command:

```plaintext
CONTAINER ID   IMAGE      COMMAND                  CREATED         STATUS         PORTS                    NAMES
df957c58a6a3   postgres   "docker-entrypoint.s…"   4 seconds ago   Up 3 seconds   0.0.0.0:5432->5432/tcp   drizzle-postgres
```

#### Configure database url

To connect to the PostgreSQL database, you need to provide the database URL. The URL format is:

```plaintext
postgres://<user>:<password>@<host>:<port>/<database>
```

You should replace placeholders with your actual values. For example, for created container the url will be:

```plaintext
postgres://postgres:mypassword@localhost:5432/postgres
```

Now you can connect to the database using the URL in your application.
</Steps>


Source: https://orm.drizzle.team/docs/guides/seeding-using-with-option


import IsSupportedChipGroup from "@mdx/IsSupportedChipGroup.astro";
import Prerequisites from "@mdx/Prerequisites.astro";
import CodeTabs from '@mdx/CodeTabs.astro';
import CodeTab from '@mdx/CodeTab.astro';
import Callout from '@mdx/Callout.astro';
import Section from "@mdx/Section.astro";

<IsSupportedChipGroup chips={{PostgreSQL: true, MySQL: true, SQLite: true, MSSQL: true, Cockroach: true}}/>

<Prerequisites>
- Get started with [PostgreSQL](/docs/get-started-postgresql), [MySQL](/docs/mysql/get-started-mysql), [SQLite](/docs/sqlite/get-started-sqlite), [MSSQL](/docs/mssql/get-started-mssql) and [Cockroach](/docs/cockroach/get-started-cockroach)
- Get familiar with [One-to-many Relation](/docs/relations#one-to-many)
- Get familiar with [Drizzle Seed](/docs/seed-overview)
</Prerequisites>

<Callout title='Warning'>
Using `with` implies tables to have a one-to-many relationship.

Therefore, if `one` user has `many` posts, you can use `with` as follows:
```ts
users: {
    count: 2,
    with: {
        posts: 3,
    },
},
```
</Callout>

## Example 1
<CodeTabs items={["index.ts", "schema.ts"]}>
<CodeTab>
```ts
import { users, posts } from './schema.ts';

async function main() {
    const db = drizzle(...);
    await seed(db, { users, posts }).refine(() => ({
        users: {
            count: 2,
            with: {
                posts: 3,
            },
        },
    }));
}
main();

```
</CodeTab>

<CodeTab>
```ts
import { serial, pgTable, integer, text } from "drizzle-orm/pg-core";

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

export const posts = pgTable('posts', {
	id: serial('id').primaryKey(),
	content: text('content'),
	authorId: integer('author_id').notNull(),
});
```
</CodeTab>
</CodeTabs>

Running the seeding script above will cause an error.

```
Error: "posts" table doesn't have a reference to "users" table or
you didn't include your one-to-many relation in the seed function schema.
You can't specify "posts" as parameter in users.with object.
```

You will have several options to resolve an error:
- You can add reference to the `authorId` column in `posts` table in your schema
<CodeTabs items={["index.ts", "schema.ts"]}>
<CodeTab>
<Section>
```ts
import { users, posts } from './schema.ts';

async function main() {
    const db = drizzle(...);
    await seed(db, { users, posts }).refine(() => ({
        users: {
            count: 2,
            with: {
                posts: 3,
            },
        },
    }));
}
main();

// Running the seeding script above will fill you database with values shown below
```

```mdx
`users`

| id |   name   |   
| -- | -------- |
|  1 | 'Melanny' | 
|  2 | 'Elvera' |

`posts`

| id |        content        | author_id |   
| -- | --------------------- | --------- |
|  1 | 'tf02gUXb0LZIdEg6SL'  |     2     |
|  2 | 'j15YdT7Sma'          |     2     |
|  3 | 'LwwvWtLLAZzIpk'      |     1     |
|  4 | 'mgyUnBKSrQw'         |     1     |
|  5 | 'CjAJByKIqilHcPjkvEw' |     2     |
|  6 | 'S5g0NzXs'            |     1     |
```
</Section>
</CodeTab>
<CodeTab>
```ts copy{11}
import { serial, pgTable, integer, text } from "drizzle-orm/pg-core";

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

export const posts = pgTable('posts', {
	id: serial('id').primaryKey(),
	content: text('content'),
	authorId: integer('author_id').notNull().references(() => users.id),
});
```
</CodeTab>
</CodeTabs>

- You can add one-to-many relation to your schema and include it in the seed function schema
<CodeTabs items={["index.ts", "schema.ts"]}>
<CodeTab>
<Section>
```ts copy{1,5}
import { users, posts, postsRelations } from './schema.ts';

async function main() {
    const db = drizzle(...);
    await seed(db, { users, posts, postsRelations }).refine(() => ({
        users: {
            count: 2,
            with: {
                posts: 3,
            },
        },
    }));
}
main();

// Running the seeding script above will fill you database with values shown below
```

```mdx
`users`

| id |   name   |   
| -- | -------- |
|  1 | 'Melanny' | 
|  2 | 'Elvera' |

`posts`

| id |        content        | author_id |   
| -- | --------------------- | --------- |
|  1 | 'tf02gUXb0LZIdEg6SL'  |     2     |
|  2 | 'j15YdT7Sma'          |     2     |
|  3 | 'LwwvWtLLAZzIpk'      |     1     |
|  4 | 'mgyUnBKSrQw'         |     1     |
|  5 | 'CjAJByKIqilHcPjkvEw' |     2     |
|  6 | 'S5g0NzXs'            |     1     |
```
</Section>
</CodeTab>

<CodeTab>
```ts copy{2,15-20}
import { serial, pgTable, integer, text } from "drizzle-orm/pg-core";
import { relations } from "drizzle-orm";

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

export const posts = pgTable('posts', {
	id: serial('id').primaryKey(),
	content: text('content'),
	authorId: integer('author_id').notNull(),
});

export const postsRelations = relations(posts, ({ one }) => ({
	author: one(users, {
		fields: [posts.authorId],
		references: [users.id],
	}),
}));
```
</CodeTab>
</CodeTabs>


## Example 2
<CodeTabs items={["index.ts", "schema.ts"]}>
<CodeTab>
```ts
import { users, posts } from './schema.ts';

async function main() {
    const db = drizzle(...);
    await seed(db, { users, posts }).refine(() => ({
        posts: {
            count: 2,
            with: {
                users: 3,
            },
        },
    }));
}
main();

```
</CodeTab>

<CodeTab>
```ts
import { serial, pgTable, integer, text } from "drizzle-orm/pg-core";

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

export const posts = pgTable('posts', {
	id: serial('id').primaryKey(),
	content: text('content'),
	authorId: integer('author_id').notNull().references(() => users.id),
});
```
</CodeTab>
</CodeTabs>

Running the seeding script above will cause an error.

```
Error: "posts" table doesn't have a reference to "users" table or
you didn't include your one-to-many relation in the seed function schema.
You can't specify "posts" as parameter in users.with object.
```

<Callout title='Why?'>
You have a `posts` table referencing a `users` table in your schema, 
```ts copy{7}
.
.
.
export const posts = pgTable('posts', {
	id: serial('id').primaryKey(),
	content: text('content'),
	authorId: integer('author_id').notNull().references(() => users.id),
});
```
or in other words, you have one-to-many relation where `one` user can have `many` posts.

However, in your seeding script, you're attempting to generate 3 (`many`) users for `one` post.
```ts
posts: {
    count: 2,
    with: {
        users: 3,
    },
},
```
</Callout>

To resolve the error, you can modify your seeding script as follows:
<Section>
```ts copy{6-9}
import { users, posts, postsRelations } from './schema.ts';

async function main() {
    const db = drizzle(...);
    await seed(db, { users, posts, postsRelations }).refine(() => ({
        users: {
            count: 2,
            with: {
                posts: 3,
            },
        },
    }));
}
main();

// Running the seeding script above will fill you database with values shown below
```

```mdx
`users`

| id |   name   |   
| -- | -------- |
|  1 | 'Melanny' | 
|  2 | 'Elvera' |

`posts`

| id |        content        | author_id |   
| -- | --------------------- | --------- |
|  1 | 'tf02gUXb0LZIdEg6SL'  |     2     |
|  2 | 'j15YdT7Sma'          |     2     |
|  3 | 'LwwvWtLLAZzIpk'      |     1     |
|  4 | 'mgyUnBKSrQw'         |     1     |
|  5 | 'CjAJByKIqilHcPjkvEw' |     2     |
|  6 | 'S5g0NzXs'            |     1     |
```
</Section>

## Example 3

<CodeTabs items={["index.ts", "schema.ts"]}>
<CodeTab>
```ts copy{6-9}
import { users } from './schema.ts';

async function main() {
    const db = drizzle(...);
    await seed(db, { users }).refine(() => ({
        users: {
            count: 2,
            with: {
                users: 3,
            },
        },
    }));
}
main();

```
</CodeTab>

<CodeTab>
```ts
import { serial, pgTable, integer, text } from "drizzle-orm/pg-core";
import type { AnyPgColumn } from "drizzle-orm/pg-core";

export const users = pgTable('users', {
	id: serial('id').primaryKey(),
	name: text('name'),
    reportsTo: integer('reports_to').references((): AnyPgColumn => users.id),
});
```
</CodeTab>
</CodeTabs>

Running the seeding script above will cause an error.

```
Error: "users" table has self reference.
You can't specify "users" as parameter in users.with object.
```

<Callout title='Why?'>
You have a `users` table referencing a `users` table in your schema, 
```ts copy{7}
.
.
.
export const users = pgTable('users', {
	id: serial('id').primaryKey(),
	name: text('name'),
    reportsTo: integer('reports_to').references((): AnyPgColumn => users.id),
});
```
or in other words, you have one-to-one relation where `one` user can have only `one` user.

However, in your seeding script, you're attempting to generate 3 (`many`) users for `one` user, which is impossible.
```ts
users: {
    count: 2,
    with: {
        users: 3,
    },
},
```
</Callout>

Source: https://orm.drizzle.team/docs/guides/seeding-with-partially-exposed-schema


import IsSupportedChipGroup from "@mdx/IsSupportedChipGroup.astro";
import Prerequisites from "@mdx/Prerequisites.astro";
import CodeTabs from '@mdx/CodeTabs.astro';
import CodeTab from '@mdx/CodeTab.astro';
import Callout from '@mdx/Callout.astro';

<IsSupportedChipGroup chips={{PostgreSQL: true, MySQL: true, SQLite: true, MSSQL: true, Cockroach: true}}/>

<Prerequisites>
- Get started with [PostgreSQL](/docs/get-started-postgresql), [MySQL](/docs/mysql/get-started-mysql), [SQLite](/docs/sqlite/get-started-sqlite), [MSSQL](/docs/mssql/get-started-mssql) and [Cockroach](/docs/cockroach/get-started-cockroach)
- Get familiar with [Drizzle Seed](/docs/seed-overview)
</Prerequisites>

## Example 1
Let's assume you are trying to seed your database using the seeding script and schema shown below.
<CodeTabs items={["index.ts", "schema.ts"]}>
<CodeTab>
```ts
import { bloodPressure } from './schema.ts';

async function main() {
  const db = drizzle(...);
  await seed(db, { bloodPressure });
}
main();

```
</CodeTab>

<CodeTab>
```ts copy {10}
import { serial, pgTable, integer, doublePrecision } from "drizzle-orm/pg-core";

export const users = pgTable("users", {
    id: serial("id").primaryKey(),
});

export const bloodPressure = pgTable("bloodPressure", {
	bloodPressureId: serial().primaryKey(),
	pressure: doublePrecision(),
	userId: integer().references(() => users.id).notNull(),
})
```
</CodeTab>
</CodeTabs>
If the `bloodPressure` table has a not-null constraint on the `userId` column, running the seeding script will cause an error.

```
Error: Column 'userId' has not null constraint, 
and you didn't specify a table for foreign key on column 'userId' in 'bloodPressure' table.
```

<Callout title='What does it mean?'>
This means we can't fill the `userId` column with Null values due to the not-null constraint on that column. 
Additionally, you didn't expose the `users` table to the `seed` function schema, so we can't generate `users.id` to populate the `userId` column with these values.
</Callout>


At this point, you have several options to resolve the error:
- You can remove the not-null constraint from the `userId` column;
- You can expose `users` table to `seed` function schema
```ts 
await seed(db, { bloodPressure, users });
```
- You can [refine](/docs/guides/seeding-with-partially-exposed-schema#refining-the-userid-column-generator) the `userId` column generator;

## Example 2

<CodeTabs items={["index.ts", "schema.ts"]}>
<CodeTab>
```ts
import { bloodPressure } from './schema.ts';

async function main() {
  const db = drizzle(...);
  await seed(db, { bloodPressure });
}
main();

```
</CodeTab>

<CodeTab>
```ts copy {10}
import { serial, pgTable, integer, doublePrecision } from "drizzle-orm/pg-core";

export const users = pgTable("users", {
    id: serial("id").primaryKey(),
});

export const bloodPressure = pgTable("bloodPressure", {
	bloodPressureId: serial().primaryKey(),
	pressure: doublePrecision(),
	userId: integer().references(() => users.id),
})
```
</CodeTab>
</CodeTabs>

By running the seeding script above you will see a warning
```
Column 'userId' in 'bloodPressure' table will be filled with Null values
because you specified neither a table for foreign key on column 'userId' 
nor a function for 'userId' column in refinements.
```
<Callout title='What does it mean?'>
This means you neither provided the `users` table to the `seed` function schema nor refined the `userId` column generator. 
As a result, the `userId` column will be filled with Null values.
</Callout>
Then you will have two choices:
- If you're okay with filling the `userId` column with Null values, you can ignore the warning;

- Otherwise, you can [refine](/docs/guides/seeding-with-partially-exposed-schema#refining-the-userid-column-generator) the `userId` column generator. 

## Refining the `userId` column generator
Doing so requires the `users` table to already have IDs such as 1 and 2 in the database.
<CodeTabs items={["index.ts"]}>
<CodeTab>
```ts copy {8}
import { bloodPressure } from './schema.ts';

async function main() {
  const db = drizzle(...);
  await seed(db, { bloodPressure }).refine((funcs) => ({
    bloodPressure: {
      columns: {
        userId: funcs.valuesFromArray({ values: [1, 2] })
      }
    }
  }));
}
main();

```
</CodeTab>
</CodeTabs>


Source: https://orm.drizzle.team/docs/guides/select-parent-rows-with-at-least-one-related-child-row


import Prerequisites from "@mdx/Prerequisites.astro";
import IsSupportedChipGroup from "@mdx/IsSupportedChipGroup.astro";
import CodeTabs from '@mdx/CodeTabs.astro';
import CodeTab from '@mdx/CodeTab.astro';
import Section from "@mdx/Section.astro";

<IsSupportedChipGroup chips={{PostgreSQL: true, MySQL: true, SQLite: true, MSSQL: true, Cockroach: true}}/>

<Prerequisites>
- Get started with [PostgreSQL](/docs/get-started-postgresql), [MySQL](/docs/mysql/get-started-mysql), [SQLite](/docs/sqlite/get-started-sqlite), [MSSQL](/docs/mssql/get-started-mssql) and [Cockroach](/docs/cockroach/get-started-cockroach)
- [Select statement](/docs/select) and [select from subquery](/docs/select#select-from-subquery)
- [Inner join](/docs/joins#inner-join)
- [Filter operators](/docs/operators) and [exists function](/docs/operators#exists)
</Prerequisites>

This guide demonstrates how to select parent rows with the condition of having at least one related child row. Below, there are examples of schema definitions and the corresponding database data:

  ```ts copy
  import { integer, pgTable, serial, text } from 'drizzle-orm/pg-core';

  export const users = pgTable('users', {
    id: serial('id').primaryKey(),
    name: text('name').notNull(),
    email: text('email').notNull(),
  });

  export const posts = pgTable('posts', {
    id: serial('id').primaryKey(),
    title: text('title').notNull(),
    content: text('content').notNull(),
    userId: integer('user_id').notNull().references(() => users.id),
  });
  ```

<CodeTabs items={["users.db", "posts.db"]}>
  <CodeTab>
    ```plaintext
    +----+------------+----------------------+
    | id |    name    |        email         |
    +----+------------+----------------------+
    |  1 | John Doe   | john_doe@email.com   |
    +----+------------+----------------------+
    |  2 | Tom Brown  | tom_brown@email.com  |
    +----+------------+----------------------+
    |  3 | Nick Smith | nick_smith@email.com |
    +----+------------+----------------------+
    ```
  </CodeTab>

  <CodeTab>
    ```plaintext
    +----+--------+-----------------------------+---------+
    | id | title  |          content            | user_id |
    +----+--------+-----------------------------+---------+
    |  1 | Post 1 | This is the text of post 1  |       1 |
    +----+--------+-----------------------------+---------+
    |  2 | Post 2 | This is the text of post 2  |       1 |
    +----+--------+-----------------------------+---------+
    |  3 | Post 3 | This is the text of post 3  |       3 |
    +----+--------+-----------------------------+---------+
    ```
  </CodeTab>
</CodeTabs>

To select parent rows with at least one related child row and retrieve child data you can use `.innerJoin()` method:

<Section>
  ```ts copy {12}
  import { eq } from 'drizzle-orm';
  import { users, posts } from './schema';

  const db = drizzle(...);

  await db
    .select({
      user: users,
      post: posts,
    })
    .from(users)
    .innerJoin(posts, eq(users.id, posts.userId));
    .orderBy(users.id);
  ```

  ```sql
  select users.*, posts.* from users
    inner join posts on users.id = posts.user_id
    order by users.id;
  ```

  ```ts
  // result data, there is no user with id 2 because he has no posts
  [
    {
      user: { id: 1, name: 'John Doe', email: 'john_doe@email.com' },
      post: {
        id: 1,
        title: 'Post 1',
        content: 'This is the text of post 1',
        userId: 1
      }
    },
    {
      user: { id: 1, name: 'John Doe', email: 'john_doe@email.com' },
      post: {
        id: 2,
        title: 'Post 2',
        content: 'This is the text of post 2',
        userId: 1
      }
    },
    {
      user: { id: 3, name: 'Nick Smith', email: 'nick_smith@email.com' },
      post: {
        id: 3,
        title: 'Post 3',
        content: 'This is the text of post 3',
        userId: 3
      }
    }
  ]
  ```
</Section>

To only select parent rows with at least one related child row you can use subquery with `exists()` function like this:

<Section>
```ts copy {8}
import { eq, exists, sql } from 'drizzle-orm';

const sq = db
  .select({ id: sql`1` })
  .from(posts)
  .where(eq(posts.userId, users.id));

await db.select().from(users).where(exists(sq));
```

```sql
select * from users where exists (select 1 from posts where posts.user_id = users.id);
```

```ts
// result data, there is no user with id 2 because he has no posts
[
  { id: 1, name: 'John Doe', email: 'john_doe@email.com' },
  { id: 3, name: 'Nick Smith', email: 'nick_smith@email.com' }
]
```
</Section>


Source: https://orm.drizzle.team/docs/guides/timestamp-default-value


import Section from "@mdx/Section.astro";
import Prerequisites from "@mdx/Prerequisites.astro";
import CodeTabs from '@mdx/CodeTabs.astro';
import CodeTab from '@mdx/CodeTab.astro';

<Prerequisites>
- Get started with [PostgreSQL](/docs/get-started-postgresql), [MySQL](/docs/mysql/get-started-mysql) and [SQLite](/docs/sqlite/get-started-sqlite)
- Learn about column data types for [PostgreSQL](/docs/column-types), [MySQL](/docs/mysql/column-types) and [SQLite](/docs/sqlite/column-types)
- [sql operator](/docs/sql)
</Prerequisites>

### PostgreSQL

To set current timestamp as a default value in PostgreSQL, you can use the `defaultNow()` method or `sql` operator with `now()` function which returns the current date and time with the time zone:

<Section>
```ts copy {6,9}
import { sql } from 'drizzle-orm';
import { timestamp, pgTable, serial } from 'drizzle-orm/pg-core';

export const users = pgTable('users', {
  id: serial('id').primaryKey(),
  timestamp1: timestamp('timestamp1').notNull().defaultNow(),
  timestamp2: timestamp('timestamp2', { mode: 'string' })
    .notNull()
    .default(sql`now()`),
});
```

```sql
CREATE TABLE IF NOT EXISTS "users" (
	"id" serial PRIMARY KEY NOT NULL,
	"timestamp1" timestamp DEFAULT now() NOT NULL,
	"timestamp2" timestamp DEFAULT now() NOT NULL
);
```
</Section>

The `mode` option defines how values are handled in the application. Values with `string` mode are treated as `string` in the application, but stored as timestamps in the database.

<Section>
```plaintext
// Data stored in the database
+----+----------------------------+----------------------------+
| id |         timestamp1         |         timestamp2         |
+----+----------------------------+----------------------------+
| 1  | 2024-04-11 14:14:28.038697 | 2024-04-11 14:14:28.038697 |
+----+----------------------------+----------------------------+
```

```ts
// Data returned by the application
[
  {
    id: 1,
    timestamp1: 2024-04-11T14:14:28.038Z, // Date object
    timestamp2: '2024-04-11 14:14:28.038697' // string
  }
]
```
</Section>

To set unix timestamp as a default value in PostgreSQL, you can use the `sql` operator and `extract(epoch from now())` function which returns the number of seconds since `1970-01-01 00:00:00 UTC`:

<Section>
```ts copy {8}
import { sql } from 'drizzle-orm';
import { integer, pgTable, serial } from 'drizzle-orm/pg-core'

export const users = pgTable('users', {
  id: serial('id').primaryKey(),
  timestamp: integer('timestamp')
    .notNull()
    .default(sql`extract(epoch from now())`),
});
```

```sql
CREATE TABLE IF NOT EXISTS "users" (
	"id" serial PRIMARY KEY NOT NULL,
	"timestamp" integer DEFAULT extract(epoch from now()) NOT NULL
);
```

```plaintext
// Data stored in the database
+----+------------+
| id | timestamp  |
+----+------------+
|  1 | 1712846784 |
+----+------------+
```

```ts
// Data returned by the application
[ 
  { 
    id: 1, 
    timestamp: 1712846784 // number
  } 
]
```
</Section>


### MySQL

To set current timestamp as a default value in MySQL, you can use the `defaultNow()` method or `sql` operator with `now()` function which returns the current date and time `(YYYY-MM-DD HH-MM-SS)`:

<Section>
```ts copy {6,9,12}
import { sql } from 'drizzle-orm';
import { mysqlTable, serial, timestamp } from 'drizzle-orm/mysql-core';

export const users = mysqlTable('users', {
  id: serial('id').primaryKey(),
  timestamp1: timestamp('timestamp1').notNull().defaultNow(),
  timestamp2: timestamp('timestamp2', { mode: 'string' })
    .notNull()
    .default(sql`now()`),
  timestamp3: timestamp('timestamp3', { fsp: 3 }) // fractional seconds part
    .notNull()
    .default(sql`now(3)`),
});
```

```sql
CREATE TABLE `users` (
	`id` serial AUTO_INCREMENT NOT NULL,
	`timestamp1` timestamp NOT NULL DEFAULT now(),
	`timestamp2` timestamp NOT NULL DEFAULT now(),
	`timestamp3` timestamp(3) NOT NULL DEFAULT now(3),
	CONSTRAINT `users_id` PRIMARY KEY(`id`)
);
```
</Section>

`fsp` option defines the number of fractional seconds to include in the timestamp. The default value is `0`.
The `mode` option defines how values are handled in the application. Values with `string` mode are treated as `string` in the application, but stored as timestamps in the database.

<Section>
```plaintext
// Data stored in the database
+----+---------------------+---------------------+-------------------------+
| id | timestamp1          | timestamp2          | timestamp3              |
+----+---------------------+---------------------+-------------------------+
|  1 | 2024-04-11 15:24:53 | 2024-04-11 15:24:53 | 2024-04-11 15:24:53.236 |
+----+---------------------+---------------------+-------------------------+
```

```ts
// Data returned by the application
[
  {
    id: 1,
    timestamp1: 2024-04-11T15:24:53.000Z, // Date object
    timestamp2: '2024-04-11 15:24:53', // string
    timestamp3: 2024-04-11T15:24:53.236Z // Date object
  }
]
```
</Section>

To set unix timestamp as a default value in MySQL, you can use the `sql` operator and `unix_timestamp()` function which returns the number of seconds since `1970-01-01 00:00:00 UTC`:

<Section>
```ts copy {8}
import { sql } from 'drizzle-orm';
import { mysqlTable, serial, int } from 'drizzle-orm/mysql-core';

export const users = mysqlTable('users', {
  id: serial('id').primaryKey(),
  timestamp: int('timestamp')
    .notNull()
    .default(sql`(unix_timestamp())`),
});
```

```sql
CREATE TABLE `users` (
	`id` serial AUTO_INCREMENT NOT NULL,
	`timestamp` int NOT NULL DEFAULT (unix_timestamp()),
	CONSTRAINT `users_id` PRIMARY KEY(`id`)
);
```

```plaintext
// Data stored in the database
+----+------------+
| id | timestamp  |
+----+------------+
|  1 | 1712847986 |
+----+------------+
```

```ts
// Data returned by the application
[ 
  { 
    id: 1, 
    timestamp: 1712847986 // number
  } 
]
```
</Section>

### SQLite

To set current timestamp as a default value in SQLite, you can use `sql` operator with `current_timestamp` constant which returns text representation of the current UTC date and time `(YYYY-MM-DD HH:MM:SS)`:

<Section>
```ts copy {8}
import { sql } from 'drizzle-orm';
import { integer, sqliteTable, text } from 'drizzle-orm/sqlite-core';

export const users = sqliteTable('users', {
  id: integer('id').primaryKey(),
  timestamp: text('timestamp')
    .notNull()
    .default(sql`(current_timestamp)`),
});
```

```sql
CREATE TABLE `users` (
	`id` integer PRIMARY KEY NOT NULL,
	`timestamp` text DEFAULT (current_timestamp) NOT NULL
);
```

```plaintext
// Data stored in the database
+----+---------------------+
| id | timestamp           |
+----+---------------------+
|  1 | 2024-04-11 15:40:43 |
+----+---------------------+
```

```ts
// Data returned by the application
[
  {
    id: 1,
    timestamp: '2024-04-11 15:40:43' // string
  }
]
```
</Section>

To set unix timestamp as a default value in SQLite, you can use the `sql` operator and `unixepoch()` function which returns the number of seconds since `1970-01-01 00:00:00 UTC`:

<Section>
```ts copy {8,11,14}
import { sql } from 'drizzle-orm';
import { integer, sqliteTable } from 'drizzle-orm/sqlite-core';

export const users = sqliteTable('users', {
  id: integer('id').primaryKey(),
  timestamp1: integer('timestamp1', { mode: 'timestamp' })
    .notNull()
    .default(sql`(unixepoch())`),
  timestamp2: integer('timestamp2', { mode: 'timestamp_ms' })
    .notNull()
    .default(sql`(unixepoch('subsecond') * 1000)`),
  timestamp3: integer('timestamp3', { mode: 'number' })
    .notNull()
    .default(sql`(unixepoch())`),
});
```

```sql
CREATE TABLE `users` (
	`id` integer PRIMARY KEY NOT NULL,
	`timestamp1` integer DEFAULT (unixepoch()) NOT NULL,
	`timestamp2` integer DEFAULT (unixepoch('subsecond') * 1000) NOT NULL,
	`timestamp3` integer DEFAULT (unixepoch()) NOT NULL
);
```
</Section>

The `mode` option defines how values are handled in the application. In the application, values with `timestamp` and `timestamp_ms` modes are treated as `Date` objects, but stored as integers in the database.
The difference is that `timestamp` handles seconds, while `timestamp_ms` handles milliseconds.

<Section>
```plaintext
// Data stored in the database
+------------+------------+---------------+------------+
| id         | timestamp1 | timestamp2    | timestamp3 |
+------------+------------+---------------+------------+
| 1          | 1712835640 | 1712835640469 | 1712835640 |
+------------+------------+---------------+------------+
```

```ts
// Data returned by the application
[
  {
    id: 1,
    timestamp1: 2024-04-11T11:40:40.000Z, // Date object
    timestamp2: 2024-04-11T11:40:40.469Z, // Date object
    timestamp3: 1712835640 // number
  }
]
```
</Section>


Source: https://orm.drizzle.team/docs/guides/toggling-a-boolean-field

import Section from "@mdx/Section.astro";
import IsSupportedChipGroup from "@mdx/IsSupportedChipGroup.astro";
import Prerequisites from "@mdx/Prerequisites.astro";

<IsSupportedChipGroup chips={{PostgreSQL: true, MySQL: true, SQLite: true, MSSQL: true, Cockroach: true}}/>

<Prerequisites>
- Get started with [PostgreSQL](/docs/get-started-postgresql), [MySQL](/docs/mysql/get-started-mysql), [SQLite](/docs/sqlite/get-started-sqlite), [MSSQL](/docs/mssql/get-started-mssql) and [Cockroach](/docs/cockroach/get-started-cockroach)
- [Update statement](/docs/update)
- [Filters](/docs/operators) and [not operator](/docs/operators#not)
- Boolean data type in [MySQL](/docs/mysql/column-types#boolean) and [SQLite](/docs/sqlite/column-types#boolean)
</Prerequisites>

To toggle a column value you can use `update().set()` method like below:

<Section>
```tsx copy {8}
import { eq, not } from 'drizzle-orm';

const db = drizzle(...);

await db
  .update(table)
  .set({
    isActive: not(table.isActive),
  })
  .where(eq(table.id, 1));
```

```sql
update "table" set "is_active" = not "is_active" where "id" = 1;
```
</Section>

Please note that there is no boolean type in MySQL and SQLite.
MySQL uses tinyint(1).
SQLite uses integers 0 (false) and 1 (true). 


Source: https://orm.drizzle.team/docs/guides/unique-case-insensitive-email


import Section from "@mdx/Section.astro";
import Prerequisites from "@mdx/Prerequisites.astro";
import CodeTabs from '@mdx/CodeTabs.astro';
import CodeTab from '@mdx/CodeTab.astro';
import Callout from '@mdx/Callout.astro';

<Prerequisites>
- Get started with [PostgreSQL](/docs/get-started-postgresql), [MySQL](/docs/mysql/get-started-mysql) and [SQLite](/docs/sqlite/get-started-sqlite)
- [Indexes](/docs/indexes-constraints#indexes)
- [Insert statement](/docs/insert) and [Select method](/docs/select)
- [sql operator](/docs/sql)
- You should have `drizzle-orm@0.31.0` and `drizzle-kit@0.22.0` or higher.
</Prerequisites>

### PostgreSQL

To implement a unique and case-insensitive `email` handling in PostgreSQL with Drizzle, you can create a unique index on the lowercased `email` column. This way, you can ensure that the `email` is unique regardless of the case.

Drizzle has simple and flexible API, which lets you easily create such an index using SQL-like syntax:
<CodeTabs items={["schema.ts", "migration.sql"]}>
  <CodeTab>
  ```ts copy {12,13}
  import { SQL, sql } from 'drizzle-orm';
  import { AnyPgColumn, pgTable, serial, text, uniqueIndex } from 'drizzle-orm/pg-core';

  export const users = pgTable(
    'users',
    {
      id: serial('id').primaryKey(),
      name: text('name').notNull(),
      email: text('email').notNull(),
    },
    (table) => [
      // uniqueIndex('emailUniqueIndex').on(sql`lower(${table.email})`),
      uniqueIndex('emailUniqueIndex').on(lower(table.email)),
    ],
  );

  // custom lower function
  export function lower(email: AnyPgColumn): SQL {
    return sql`lower(${email})`;
  }
  ```
  </CodeTab>
  ```sql
  CREATE TABLE IF NOT EXISTS "users" (
	"id" serial PRIMARY KEY NOT NULL,
	"name" text NOT NULL,
	"email" text NOT NULL
  );
  --> statement-breakpoint
  CREATE UNIQUE INDEX IF NOT EXISTS "emailUniqueIndex" ON "users" USING btree (lower("email"));
  ```
</CodeTabs>

This is how you can select user by `email` with `lower` function:

<Section>
```ts copy {10}
import { eq } from 'drizzle-orm';
import { lower, users } from './schema';

const db = drizzle(...);

const findUserByEmail = async (email: string) => {
  return await db
    .select()
    .from(users)
    .where(eq(lower(users.email), email.toLowerCase()));
};
```

```sql
select * from "users" where lower(email) = 'john@email.com';
```
</Section>

### MySQL

In MySQL, the default collation setting for string comparison is case-insensitive, which means that when performing operations like searching or comparing strings in SQL queries, the case of the characters does not affect the results. However, because collation settings can vary and may be configured to be case-sensitive, we will explicitly ensure that the `email` is unique regardless of case by creating a unique index on the lowercased `email` column.

Drizzle has simple and flexible API, which lets you easily create such an index using SQL-like syntax:
<CodeTabs items={["schema.ts", "migration.sql"]}>
  <CodeTab>
  ```ts copy {12,13}
  import { SQL, sql } from 'drizzle-orm';
  import { AnyMySqlColumn, mysqlTable, serial, uniqueIndex, varchar } from 'drizzle-orm/mysql-core';

  export const users = mysqlTable(
    'users',
    {
      id: serial('id').primaryKey(),
      name: varchar('name', { length: 255 }).notNull(),
      email: varchar('email', { length: 255 }).notNull(),
    },
    (table) => [
      // uniqueIndex('emailUniqueIndex').on(sql`(lower(${table.email}))`),
      uniqueIndex('emailUniqueIndex').on(lower(table.email)),
    ]
  );

  // custom lower function
  export function lower(email: AnyMySqlColumn): SQL {
    return sql`(lower(${email}))`;
  }
  ```
  </CodeTab>
  ```sql
  CREATE TABLE `users` (
	  `id` serial AUTO_INCREMENT NOT NULL,
	  `name` varchar(255) NOT NULL,
	  `email` varchar(255) NOT NULL,
	  CONSTRAINT `users_id` PRIMARY KEY(`id`),
	  CONSTRAINT `emailUniqueIndex` UNIQUE((lower(`email`)))
  );
  ```
</CodeTabs>

<Callout type="warning">
Functional indexes are supported in MySQL starting from version `8.0.13`. For the correct syntax, the expression should be enclosed in parentheses, for example, `(lower(column))`.
</Callout>

This is how you can select user by `email` with `lower` function:

<Section>
```ts copy {10}
import { eq } from 'drizzle-orm';
import { lower, users } from './schema';

const db = drizzle(...);

const findUserByEmail = async (email: string) => {
  return await db
    .select()
    .from(users)
    .where(eq(lower(users.email), email.toLowerCase()));
};
```

```sql
select * from `users` where lower(email) = 'john@email.com';
```
</Section>

### SQLite

To implement a unique and case-insensitive `email` handling in SQLite with Drizzle, you can create a unique index on the lowercased `email` column. This way, you can ensure that the `email` is unique regardless of the case.

Drizzle has simple and flexible API, which lets you easily create such an index using SQL-like syntax:

<CodeTabs items={["schema.ts", "migration.sql"]}>
  <CodeTab>
  ```ts copy {12,13}
  import { SQL, sql } from 'drizzle-orm';
  import { AnySQLiteColumn, integer, sqliteTable, text, uniqueIndex } from 'drizzle-orm/sqlite-core';

  export const users = sqliteTable(
    'users',
    {
      id: integer('id').primaryKey(),
      name: text('name').notNull(),
      email: text('email').notNull(),
    },
    (table) => [
      // uniqueIndex('emailUniqueIndex').on(sql`lower(${table.email})`),
      uniqueIndex('emailUniqueIndex').on(lower(table.email)),
    ]
  );

  // custom lower function
  export function lower(email: AnySQLiteColumn): SQL {
    return sql`lower(${email})`;
  }
  ```
  </CodeTab>
  ```sql
  CREATE TABLE `users` (
	  `id` integer PRIMARY KEY NOT NULL,
	  `name` text NOT NULL,
	  `email` text NOT NULL
  );
  --> statement-breakpoint
  CREATE UNIQUE INDEX `emailUniqueIndex` ON `users` (lower(`email`));
  ```
</CodeTabs>

This is how you can select user by `email` with `lower` function:

<Section>
```ts copy {10}
import { eq } from 'drizzle-orm';
import { lower, users } from './schema';

const db = drizzle(...);

const findUserByEmail = async (email: string) => {
  return await db
    .select()
    .from(users)
    .where(eq(lower(users.email), email.toLowerCase()));
};
```

```sql
select * from "users" where lower(email) = 'john@email.com';
```
</Section>


Source: https://orm.drizzle.team/docs/guides/update-many-with-different-value


import Section from "@mdx/Section.astro";
import Prerequisites from "@mdx/Prerequisites.astro";
import IsSupportedChipGroup from "@mdx/IsSupportedChipGroup.astro";

<IsSupportedChipGroup chips={{PostgreSQL: true, MySQL: true, SQLite: true, MSSQL: true, Cockroach: true}}/>

<Prerequisites>
- Get started with [PostgreSQL](/docs/get-started-postgresql), [MySQL](/docs/mysql/get-started-mysql), [SQLite](/docs/sqlite/get-started-sqlite), [MSSQL](/docs/mssql/get-started-mssql) and [Cockroach](/docs/cockroach/get-started-cockroach)
- [Update statement](/docs/update)
- [Filters](/docs/operators) and [sql operator](/docs/sql)
</Prerequisites>

To implement update many with different values for each row within 1 request you can use `sql` operator with `case` statement and `.update().set()` methods like this:

<Section>
```ts {26, 29, 32, 36, 38, 40}
import { SQL, inArray, sql } from 'drizzle-orm';
import { users } from './schema';

const db = drizzle(...);

const inputs = [
  {
    id: 1,
    city: 'New York',
  },
  {
    id: 2,
    city: 'Los Angeles',
  },
  {
    id: 3,
    city: 'Chicago',
  },
];

// You have to be sure that inputs array is not empty
if (inputs.length === 0) {
  return;
}

const sqlChunks: SQL[] = [];
const ids: number[] = [];

sqlChunks.push(sql`(case`);

for (const input of inputs) {
  sqlChunks.push(sql`when ${users.id} = ${input.id} then ${input.city}`);
  ids.push(input.id);
}

sqlChunks.push(sql`end)`);

const finalSql: SQL = sql.join(sqlChunks, sql.raw(' '));

await db.update(users).set({ city: finalSql }).where(inArray(users.id, ids));
```

```sql
update users set "city" = 
  (case when id = 1 then 'New York' when id = 2 then 'Los Angeles' when id = 3 then 'Chicago' end)
where id in (1, 2, 3)
```
</Section>


Source: https://orm.drizzle.team/docs/guides/upsert


import Section from "@mdx/Section.astro";
import IsSupportedChipGroup from "@mdx/IsSupportedChipGroup.astro";
import Prerequisites from "@mdx/Prerequisites.astro";
import CodeTabs from '@mdx/CodeTabs.astro';
import Callout from "@mdx/Callout.astro";
import CodeTab from '@mdx/CodeTab.astro';

<IsSupportedChipGroup chips={{PostgreSQL: true, MySQL: true, SQLite: true, MSSQL: false, Cockroach: true}}/>

<Prerequisites>
- Get started with [PostgreSQL](/docs/get-started-postgresql), [MySQL](/docs/mysql/get-started-mysql), [SQLite](/docs/sqlite/get-started-sqlite), [MSSQL](/docs/mssql/get-started-mssql) and [Cockroach](/docs/cockroach/get-started-cockroach)
- [Insert statement](/docs/insert), [onConflictDoUpdate method](/docs/insert#on-conflict-do-update) and [onDuplicateKeyUpdate method](/docs/mysql/insert#on-duplicate-key-update)
- [Composite primary key](/docs/indexes-constraints#composite-primary-key)
- [sql operator](/docs/sql)
</Prerequisites>

<Callout type="warning">
**SQL Server (MSSQL)** does not support the ***ON CONFLICT DO UPDATE*** syntax
</Callout>

### PostgreSQL, Cockroach and SQLite

To implement an upsert query in PostgreSQL, Cockroach and SQLite (skip to [MySQL](/docs/guides/upsert#mysql)) with Drizzle you can use `.onConflictDoUpdate()` method:

<Section>
```ts copy {8,9,10,11}
import { users } from './schema';

const db = drizzle(...);

await db
  .insert(users)
  .values({ id: 1, name: 'John' })
  .onConflictDoUpdate({
    target: users.id,
    set: { name: 'Super John' },
  });
```

```sql
insert into users ("id", "name") values (1, 'John')
  on conflict ("id") do update set name = 'Super John';
```
</Section>

To upsert multiple rows in one query in PostgreSQL, Cockroach and SQLite you can use `sql operator` and `excluded` keyword. `excluded` is a special reference that refer to the row that was proposed for insertion, but wasn't inserted because of the conflict.

This is how you can do it:

<CodeTabs items={["index.ts", "schema.ts"]}>
  <CodeTab>
    ```ts copy {21,24}
    import { sql } from 'drizzle-orm';
    import { users } from './schema';

    const values = [
      {
        id: 1,
        lastLogin: new Date(),
      },
      {
        id: 2,
        lastLogin: new Date(Date.now() + 1000 * 60 * 60),
      },
      {
        id: 3,
        lastLogin: new Date(Date.now() + 1000 * 60 * 120),
      },
    ];

    await db
      .insert(users)
      .values(values)
      .onConflictDoUpdate({
        target: users.id,
        set: { lastLogin: sql.raw(`excluded.${users.lastLogin.name}`) },
      });
    ```

    ```sql
    insert into users ("id", "last_login") 
      values 
        (1, '2024-03-15T22:29:06.679Z'),
        (2, '2024-03-15T23:29:06.679Z'),
        (3, '2024-03-16T00:29:06.679Z')
      on conflict ("id") do update set last_login = excluded.last_login;
    ```
  </CodeTab>
  ```ts copy
  import { pgTable, serial, timestamp } from 'drizzle-orm/pg-core';

  export const users = pgTable('users', {
    id: serial('id').primaryKey(),
    lastLogin: timestamp('last_login', { mode: 'date' }).notNull(),
  });
  ```
</CodeTabs>

Drizzle has simple and flexible API, which lets you easily create custom solutions. This is how you do custom function for updating specific columns in multiple rows due to the conflict in PostgreSQL, Cockroach and SQLite:

<CodeTabs items={["index.ts", "schema.ts"]}>
  <CodeTab>
    ```ts copy {43,46}
    import { SQL, getColumns, sql } from 'drizzle-orm';
    import { PgTable } from 'drizzle-orm/pg-core';
    import { SQLiteTable } from 'drizzle-orm/sqlite-core';
	import { CockroachTable } from "drizzle-orm/cockroach-core";
    import { users } from './schema';

    const buildConflictUpdateColumns = <
      T extends PgTable | CockroachTable | SQLiteTable,
      Q extends keyof T['_']['columns']
    >(
      table: T,
      columns: Q[],
    ) => {
      const cls = getColumns(table);

      return columns.reduce((acc, column) => {
        const colName = cls[column].name;
        acc[column] = sql.raw(`excluded.${colName}`);

        return acc;
      }, {} as Record<Q, SQL>);
    };

    const values = [
      {
        id: 1,
        lastLogin: new Date(),
        active: true,
      },
      {
        id: 2,
        lastLogin: new Date(Date.now() + 1000 * 60 * 60),
        active: true,
      },
      {
        id: 3,
        lastLogin: new Date(Date.now() + 1000 * 60 * 120),
        active: true,
      },
    ];

    await db
      .insert(users)
      .values(values)
      .onConflictDoUpdate({
        target: users.id,
        set: buildConflictUpdateColumns(users, ['lastLogin', 'active']),
      });
    ```

    ```sql
    insert into users ("id", "last_login", "active")
    values
      (1, '2024-03-16T15:44:41.141Z', true),
      (2, '2024-03-16T16:44:41.141Z', true),
      (3, '2024-03-16T17:44:41.141Z', true)
    on conflict ("id") do update set last_login = excluded.last_login, active = excluded.active;
    ```
  </CodeTab>
  ```ts copy
  import { boolean, pgTable, serial, timestamp } from 'drizzle-orm/pg-core';

  export const users = pgTable('users', {
    id: serial('id').primaryKey(),
    lastLogin: timestamp('last_login', { mode: 'date' }).notNull(),
    active: boolean('active').notNull().default(false),
  });
  ```
</CodeTabs>

This is how you can implement an upsert query with multiple targets in PostgreSQL, Cockroach and SQLite:

<Section>
```ts copy {8}
import { sql } from 'drizzle-orm';
import { inventory } from './schema';

await db
  .insert(inventory)
  .values({ warehouseId: 1, productId: 1, quantity: 100 })
  .onConflictDoUpdate({
    target: [inventory.warehouseId, inventory.productId], // composite primary key
    set: { quantity: sql`${inventory.quantity} + 100` }, // add 100 to the existing quantity
  });
```

```sql
insert into inventory ("warehouse_id", "product_id", "quantity") values (1, 1, 100)
  on conflict ("warehouse_id","product_id") do update set quantity = quantity + 100;
```
</Section>

If you want to implement upsert query with `where` clause for `update` statement, you can use `setWhere` property in `onConflictDoUpdate` method:

<CodeTabs items={["index.ts", "schema.ts"]}>
  <CodeTab>
  ```ts copy {25,26,27,28}
  import { or, sql } from 'drizzle-orm';
  import { products } from './schema';

  const data = {
    id: 1,
    title: 'Phone',
    price: '999.99',
    stock: 10,
    lastUpdated: new Date(),
  };

  const excludedPrice = sql.raw(`excluded.${products.price.name}`);
  const excludedStock = sql.raw(`excluded.${products.stock.name}`);

  await db
    .insert(products)
    .values(data)
    .onConflictDoUpdate({
      target: products.id,
      set: {
        price: excludedPrice,
        stock: excludedStock,
        lastUpdated: sql.raw(`excluded.${products.lastUpdated.name}`)
      },
      setWhere: or(
        sql`${products.stock} != ${excludedStock}`,
        sql`${products.price} != ${excludedPrice}`
      ),
    });
  ```

  ```sql
  insert into products ("id", "title", "stock", "price", "last_updated")
    values (1, 'Phone', 10, '999.99', '2024-04-29T21:56:55.563Z')
    on conflict ("id") do update
    set stock = excluded.stock, price = excluded.price, last_updated = excluded.last_updated
    where (stock != excluded.stock or price != excluded.price);
  ```
  </CodeTab>

  ```ts copy
  import { integer, numeric, pgTable, serial, text, timestamp } from 'drizzle-orm/pg-core';

  export const products = pgTable('products', {
    id: serial('id').primaryKey(),
    title: text('title').notNull(),
    stock: integer('stock').notNull(),
    price: numeric('price', { precision: 10, scale: 2 }).notNull(),
    lastUpdated: timestamp('last_updated').notNull().defaultNow(),
  });
  ```
</CodeTabs>


If you want to update all columns except of specific one, you can leave the previous value like this:

<Section>
```ts copy {16}
import { sql } from 'drizzle-orm';
import { users } from './schema';

const data = {
  id: 1,
  name: 'John',
  email: 'john@email.com',
  age: 29,
};

await db
  .insert(users)
  .values(data)
  .onConflictDoUpdate({
    target: users.id,
    set: { ...data, email: sql`${users.email}` }, // leave email as it was
});
```

```sql
insert into users ("id", "name", "email", "age") values (1, 'John', 'john@email.com', 29)
  on conflict ("id") do update set id = 1, name = 'John', email = email, age = 29;
```
</Section>

### MySQL

To implement an upsert query in MySQL with Drizzle you can use `.onDuplicateKeyUpdate()` method. MySQL will automatically determine the conflict target based on the primary key and unique indexes, and will update the row if any unique index conflicts.

This is how you can do it:

<Section>
```ts copy {4}
await db
  .insert(users)
  .values({ id: 1, name: 'John' })
  .onDuplicateKeyUpdate({ set: { name: 'Super John' } });
```

```sql
insert into users (`id`, `first_name`) values (1, 'John')
  on duplicate key update first_name = 'Super John';
```
</Section>

To upsert multiple rows in one query in MySQL you can use `sql operator` and `values()` function. `values()` function refers to the value of column that would be inserted if duplicate-key conflict hadn't occurred.  

<CodeTabs items={["index.ts", "schema.ts"]}>
  <CodeTab>
    ```ts copy {21,24}
    import { sql } from 'drizzle-orm';
    import { users } from './schema';

    const values = [
      {
        id: 1,
        lastLogin: new Date(),
      },
      {
        id: 2,
        lastLogin: new Date(Date.now() + 1000 * 60 * 60),
      },
      {
        id: 3,
        lastLogin: new Date(Date.now() + 1000 * 60 * 120),
      },
    ];

    await db
      .insert(users)
      .values(values)
      .onDuplicateKeyUpdate({
        set: {
          lastLogin: sql`values(${users.lastLogin})`,
        },
      });
    ```

    ```sql
    insert into users (`id`, `last_login`)
      values
        (1, '2024-03-15 23:08:27.025'),
        (2, '2024-03-15 00:08:27.025'),
        (3, '2024-03-15 01:08:27.025')
      on duplicate key update last_login = values(last_login);
    ```
  </CodeTab>
  ```ts copy
  import { mysqlTable, serial, timestamp } from 'drizzle-orm/mysql-core';

  export const users = mysqlTable('users', {
    id: serial('id').primaryKey(),
    lastLogin: timestamp('last_login', { mode: 'date' }).notNull(),
  });
  ```
</CodeTabs>

Drizzle has simple and flexible API, which lets you easily create custom solutions. This is how you do custom function for updating specific columns in multiple rows due to the conflict in MySQL:

<CodeTabs items={["index.ts", "schema.ts"]}>
  <CodeTab>
    ```ts copy {36,38}
    import { SQL, getColumns, sql } from 'drizzle-orm';
    import { MySqlTable } from 'drizzle-orm/mysql-core';
    import { users } from './schema';

    const buildConflictUpdateColumns = <T extends MySqlTable, Q extends keyof T['_']['columns']>(
      table: T,
      columns: Q[],
    ) => {
      const cls = getColumns(table);
      return columns.reduce((acc, column) => {
        acc[column] = sql`values(${cls[column]})`;
        return acc;
      }, {} as Record<Q, SQL>);
    };

    const values = [
      {
        id: 1,
        lastLogin: new Date(),
        active: true,
      },
      {
        id: 2,
        lastLogin: new Date(Date.now() + 1000 * 60 * 60),
        active: true,
      },
      {
        id: 3,
        lastLogin: new Date(Date.now() + 1000 * 60 * 120),
        active: true,
      },
    ];

    await db
      .insert(users)
      .values(values)
      .onDuplicateKeyUpdate({
        set: buildConflictUpdateColumns(users, ['lastLogin', 'active']),
      });
    ```

    ```sql
    insert into users (`id`, `last_login`, `active`)
      values
        (1, '2024-03-16 15:23:28.013', true),
        (2, '2024-03-16 16:23:28.013', true),
        (3, '2024-03-16 17:23:28.013', true)
      on duplicate key update last_login = values(last_login), active = values(active);
    ```
  </CodeTab>
  ```ts copy
  import { boolean, mysqlTable, serial, timestamp } from 'drizzle-orm/mysql-core';

  export const users = mysqlTable('users', {
    id: serial('id').primaryKey(),
    lastLogin: timestamp('last_login', { mode: 'date' }).notNull(),
    active: boolean('active').notNull().default(false),
  });
  ```
</CodeTabs>

If you want to update all columns except of specific one, you can leave the previous value like this:

<Section>
```ts copy {15}
import { sql } from 'drizzle-orm';
import { users } from './schema';

const data = {
  id: 1,
  name: 'John',
  email: 'john@email.com',
  age: 29,
};

await db
  .insert(users)
  .values(data)
  .onDuplicateKeyUpdate({
    set: { ...data, email: sql`${users.email}` }, // leave email as it was
});
```

```sql
insert into users (`id`, `name`, `email`, `age`) values (1, 'John', 'john@email.com', 29)
  on duplicate key update id = 1, name = 'John', email = email, age = 29;
```
</Section>


Source: https://orm.drizzle.team/docs/guides/vector-similarity-search


import Section from "@mdx/Section.astro";
import IsSupportedChipGroup from "@mdx/IsSupportedChipGroup.astro";
import Prerequisites from "@mdx/Prerequisites.astro";
import CodeTabs from '@mdx/CodeTabs.astro';
import CodeTab from '@mdx/CodeTab.astro';
import Npm from "@mdx/Npm.astro";

<Prerequisites>
- Get started with [PostgreSQL](/docs/get-started-postgresql)
- [Select statement](/docs/select)
- [Indexes](/docs/indexes-constraints#indexes)
- [sql operator](/docs/sql)
- [pgvector extension](/docs/extensions#pg_vector)
- [Drizzle kit](/docs/kit-overview)
- You should have installed the `openai` [package](https://www.npmjs.com/package/openai) for generating embeddings. 
<Npm>
  openai
</Npm>
- You should have `drizzle-orm@0.31.0` and `drizzle-kit@0.22.0` or higher.  
</Prerequisites>

To implement vector similarity search in PostgreSQL with Drizzle ORM, you can use the `pgvector` extension. This extension provides a set of functions to work with vectors and perform similarity search.

As for now, Drizzle doesn't create extension automatically, so you need to create it manually. Create an empty migration file and add SQL query:

<Section>
```bash
npx drizzle-kit generate --custom
```

```sql
CREATE EXTENSION vector;
```
</Section>

To perform similarity search, you need to create a table with a vector column and an `HNSW` or `IVFFlat` index on this column for better performance:

<CodeTabs items={["schema.ts", "migration.sql"]}>
  <CodeTab>
  ```ts copy {10, 13}
  import { index, pgTable, serial, text, vector } from 'drizzle-orm/pg-core';

  export const guides = pgTable(
    'guides',
    {
      id: serial('id').primaryKey(),
      title: text('title').notNull(),
      description: text('description').notNull(),
      url: text('url').notNull(),
      embedding: vector('embedding', { dimensions: 1536 }),
    },
    (table) => [
      index('embeddingIndex').using('hnsw', table.embedding.op('vector_cosine_ops')),
    ]
  );
  ```
  </CodeTab>
  ```sql
  CREATE TABLE IF NOT EXISTS "guides" (
    "id" serial PRIMARY KEY NOT NULL,
    "title" text NOT NULL,
    "description" text NOT NULL,
    "url" text NOT NULL,
    "embedding" vector(1536)
  );
  --> statement-breakpoint
  CREATE INDEX IF NOT EXISTS "embeddingIndex" ON "guides" USING hnsw (embedding vector_cosine_ops);
  ```
</CodeTabs>

The `embedding` column is used to store vector embeddings of the guide descriptions. Vector embedding is just a representation of some data. It converts different types of data into a common format (vectors) that language models can process. This allows us to perform mathematical operations, such as measuring the distance between two vectors, to determine how similar or different two data items are.

In this example we will use `OpenAI` model to generate [embeddings](https://platform.openai.com/docs/guides/embeddings) for the description:
```ts copy
import OpenAI from 'openai';

const openai = new OpenAI({
  apiKey: process.env['OPENAI_API_KEY'],
});

export const generateEmbedding = async (value: string): Promise<number[]> => {
  const input = value.replaceAll('\n', ' ');

  const { data } = await openai.embeddings.create({
    model: 'text-embedding-ada-002',
    input,
  });

  return data[0].embedding;
};
```

To search for similar guides by embedding, you can use `gt` and `sql` operators with `cosineDistance` function to calculate the similarity between the `embedding` column and the generated embedding:

<Section>
```ts copy {10,15,16}
import { cosineDistance, desc, gt, sql } from 'drizzle-orm';
import { generateEmbedding } from './embedding';
import { guides } from './schema';

const db = drizzle(...);

const findSimilarGuides = async (description: string) => {
  const embedding = await generateEmbedding(description);

  const similarity = sql<number>`1 - (${cosineDistance(guides.embedding, embedding)})`;

  const similarGuides = await db
    .select({ name: guides.title, url: guides.url, similarity })
    .from(guides)
    .where(gt(similarity, 0.5))
    .orderBy((t) => desc(t.similarity))
    .limit(4);

  return similarGuides;
};
```

```ts
const description = 'Guides on using Drizzle ORM with different platforms';

const similarGuides = await findSimilarGuides(description);
```

```json
[
  {
    name: 'Drizzle with Turso',
    url: '/docs/tutorials/drizzle-with-turso',
    similarity: 0.8642314333984994
  },
  {
    name: 'Drizzle with Supabase Database',
    url: '/docs/tutorials/drizzle-with-supabase',
    similarity: 0.8593631126014918
  },
  {
    name: 'Drizzle with Neon Postgres',
    url: '/docs/tutorials/drizzle-with-neon',
    similarity: 0.8541051184461372
  },
  {
    name: 'Drizzle with Vercel Edge Functions',
    url: '/docs/tutorials/drizzle-with-vercel-edge-functions',
    similarity: 0.8481551084241092
  }
]
```
</Section>


Source: https://orm.drizzle.team/docs/jit-mappers

# JIT Mappers

JIT mappers are **disabled by default**. Enable them with the `jit` option:

```ts
import { drizzle } from 'drizzle-orm/...';

const db = drizzle({ client, jit: true });
```

On initialization, Drizzle runs a compatibility check that tests whether the `Function` constructor works in the current runtime. If it doesn't (e.g. some edge runtimes or CSP-restricted environments), it falls back to regular mappers with a console warning.

The `jit` option is available in every driver's config

## What are JIT mappers?

JIT (Just-In-Time) mappers are dynamically generated JavaScript functions that transform database rows into JS objects. Instead of interpreting column metadata at runtime for every row, JIT mappers **compile a specialized function once** and reuse it for all rows in the result set.

## Why are they needed?

The regular Drizzle ORM mapper loops through column metadata for every single row:

```
For each row:
  For each column:
    → look up decoder
    → check if codec exists
    → check if value is null
    → apply codec if needed
    → apply decoder if needed
    → navigate nested path
    → assign to result object
```

With thousands of rows, this interpretive overhead adds up. JIT mappers eliminate it by generating a function where all the metadata lookups, null checks, and nested object construction are hardcoded into the function body at generation time


Source: https://orm.drizzle.team/docs/kit-migrations-for-teams

# Drizzle migrations for teams

This section will be updated right after our release of the next version of migrations folder structure. 
You can read an extended [github discussion](https://github.com/drizzle-team/drizzle-orm/discussions/2832) and subscribe to the updates!


Source: https://orm.drizzle.team/docs/kit-seed-data

import CodeTab from '@mdx/CodeTab.astro';
import CodeTabs from '@mdx/CodeTabs.astro';
import Section from '@mdx/Section.astro';
import Tab from '@mdx/Tab.astro';
import Tabs from '@mdx/Tabs.astro';
import Callout from '@mdx/Callout.astro';
import Npm from '@mdx/Npm.astro';
import Npx from '@mdx/Npx.astro';
import Steps from '@mdx/Steps.astro';
import Prerequisites from "@mdx/Prerequisites.astro"

# Drizzle Kit data seeding

This section will be updated right after our release of `drizzle-seed` package.

Source: https://orm.drizzle.team/docs/kit-web-mobile

import CodeTab from '@mdx/CodeTab.astro';
import CodeTabs from '@mdx/CodeTabs.astro';
import Section from '@mdx/Section.astro';
import Tab from '@mdx/Tab.astro';
import Tabs from '@mdx/Tabs.astro';
import Callout from '@mdx/Callout.astro';
import Npm from '@mdx/Npm.astro';
import Npx from '@mdx/Npx.astro';
import Steps from '@mdx/Steps.astro';
import Prerequisites from "@mdx/Prerequisites.astro"

# Drizzle migrations in web and mobile environments

This section will be updated in the next release.

For **Expo SQLite**, **OP SQLite** and **React Native** migrations - please refer to our [Get Started](/docs/get-started/expo-new) guide.

Source: https://orm.drizzle.team/docs/mssql/aliases

import Section from '@mdx/Section.astro';

# Aliases
Drizzle supports aliasing for tables, columns, subqueries and CTEs — mapping directly to the SQL `AS` keyword.

### Table aliasing
You can alias tables using the `alias` function. This is useful when you need to join the same table multiple times, 
for example in self-referencing relationships like employees and their managers:

<Section>
```ts copy {9}
import { alias, mssqlTable, int, text } from "drizzle-orm/mssql-core";

const employees = mssqlTable("employees", {
  id: int().identity().primaryKey(),
  name: text(),
  managerId: int("manager_id"),
});

const manager = alias(employees, "manager");

await db.select({
  employeeName: employees.name,
  managerName: manager.name,
})
  .from(employees)
  .leftJoin(manager, eq(employees.managerId, manager.id));
```
```sql
select [employees].[name], [manager].[name]
from [employees]
left join [employees] [manager] on [employees].[manager_id] = [manager].[id];
```
</Section>

### Column aliasing
You can alias columns using the `.as()` method on columns and `sql` expressions.
This maps directly to the SQL `AS` keyword and lets you control the name of a column in the query result:

<Section>
```ts {3}
const result = await db.select({
  id: users.id,
  lowerName: users.name.as("lower_name"),
}).from(users);
```
```sql
select [id], [name] as [lower_name] from [users];
```
</Section>

You can also use `.as()` with `sql` expressions:

<Section>
```ts {3}
const result = await db.select({
  id: users.id,
  lowerName: sql<string>`lower(${users.name})`.as("lower_name"),
}).from(users);
```
```sql
select [id], lower([name]) as [lower_name] from [users];
```
</Section>

### Subquery aliasing
When using a subquery as a data source, you must provide an alias using `.as()`. 
This lets you reference the subquery's columns in the outer query:

<Section>
```ts
const sq = db.select().from(users).where(eq(users.id, 42)).as('sq');

const result = await db.select().from(sq);
```
```sql
select [id], [name], [age] from (select [id], [name], [age] from [users] where [users].[id] = 42) [sq];
```
</Section>

Subqueries can also be used in joins:

<Section>
```ts
const sq = db.select().from(users).where(eq(users.id, 42)).as('sq');

const result = await db.select().from(users).leftJoin(sq, eq(users.id, sq.id));
```
```sql
select [users].[id], [users].[name], [users].[age], [sq].[id], [sq].[name], [sq].[age]
  from [users]
  left join (select [id], [name], [age] from [users] where [users].[id] = 42) [sq]
    on [users].[id] = [sq].[id];
```
</Section>

### CTE aliasing
Common table expressions (CTEs) are aliased using `db.$with('alias')`. 
The alias name is used to reference the CTE in the main query:

<Section>
```ts
const sq = db.$with('sq').as(db.select().from(users).where(eq(users.id, 42)));

const result = await db.with(sq).select().from(sq);
```
```sql
with [sq] as (select [id], [name], [age] from [users] where [users].[id] = 42)
select [id], [name], [age] from [sq];
```
</Section>

When using `sql` expressions inside a CTE, you need to alias them with `.as()` to be able to reference them in the outer query:

<Section>
```ts
const sq = db.$with('sq').as(db.select({
  name: sql<string>`upper(${users.name})`.as('name'),
}).from(users));

const result = await db.with(sq).select({ name: sq.name }).from(sq);
```
```sql
with [sq] as (select upper([name]) as [name] from [users])
select [name] from [sq];
```
</Section>

Source: https://orm.drizzle.team/docs/mssql/arktype

import Npm from '@mdx/Npm.astro';
import Callout from '@mdx/Callout.astro';

# arktype

### Install the dependencies

<Npm>
drizzle-orm@rc arktype
</Npm>

### Select schema

Defines the shape of data queried from the database - can be used to validate API responses.

```ts copy
import { int, mssqlTable, text } from 'drizzle-orm/mssql-core';
import { createSelectSchema } from 'drizzle-orm/arktype';
import type { ArkErrors } from 'arktype';

const users = mssqlTable('users', {
  id: int().primaryKey().identity(),
  name: text().notNull(),
  age: int().notNull()
});

const userSelectSchema = createSelectSchema(users);

const rows = await db.select({ id: users.id, name: users.name }).top(1).from(users);
const parsed: ArkErrors | { id: number; name: string; age: number } = userSelectSchema(rows[0]); // Error: `age` is not returned in the above query

const rows = await db.select().top(1).from(users);
const parsed: ArkErrors | { id: number; name: string; age: number } = userSelectSchema(rows[0]); // Will parse successfully
```

Views and enums are also supported.
```ts copy
import { pgEnum, pgView } from 'drizzle-orm/mssql-core';
import { gt } from 'drizzle-orm';
import { createSelectSchema } from 'drizzle-orm/arktype';
import { ArkErrors } from "arktype";

const usersView = mssqlView('users_view').as((qb) => qb.select().from(users).where(gt(users.age, 18)));
const usersViewSchema = createSelectSchema(usersView);
const parsed: ArkErrors | { id: number; name: string; age: number } = usersViewSchema(...);
```

### Insert schema

Defines the shape of data to be inserted into the database - can be used to validate API requests.

```ts copy
import { int, mssqlTable, text } from 'drizzle-orm/mssql-core';
import { createInsertSchema } from 'drizzle-orm/arktype';
import { ArkErrors } from 'arktype';

const users = mssqlTable('users', {
  id: int().primaryKey().identity(),
  name: text().notNull(),
  age: int().notNull()
});

const userInsertSchema = createInsertSchema(users);

const user = { name: 'John' };
const parsed: ArkErrors | { name: string, age: number } = userInsertSchema(user); // Error: `age` is not defined

const user = { name: 'Jane', age: 30 };
const parsed: ArkErrors | { name: string, age: number } = userInsertSchema(user); // Will parse successfully

if (parsed instanceof ArkErrors) {
  console.error(parsed.summary);
  process.exit(1);
}
await db.insert(users).values(parsed);
```

### Update schema

Defines the shape of data to be updated in the database - can be used to validate API requests.

```ts copy
import { int, mssqlTable, text } from 'drizzle-orm/mssql-core';
import { createUpdateSchema } from 'drizzle-orm/arktype';
import { parse } from 'arktype';
import { eq } from 'drizzle-orm';
import { ArkErrors } from 'arktype';

const users = mssqlTable('users', {
  id: int().primaryKey().identity(),
  name: text().notNull(),
  age: int().notNull()
});

const userUpdateSchema = createUpdateSchema(users);

const user = { age: 35 };
const parsed: ArkErrors | { name?: string | undefined, age?: number | undefined } = userUpdateSchema(user); // Will parse successfully

if (parsed instanceof ArkErrors) {
  console.error(parsed.summary);
  process.exit(1);
}

await db.update(users).set(parsed).where(eq(users.name, 'Jane'));
```

### Refinements

Each create schema function accepts an additional optional parameter that you can used to extend, modify or completely overwite a field's schema. Defining a callback function will extend or modify while providing a arktype schema will overwrite it.

```ts copy
import { int, mssqlTable, text } from 'drizzle-orm/mssql-core';
import { createSelectSchema } from 'drizzle-orm/arktype';
import { ArkErrors, type } from 'arktype';

const users = mssqlTable('users', {
  id: int().primaryKey().identity(),
  name: text().notNull(),
  bio: text(),
  preferences: text()
});

const userSelectSchema = createSelectSchema(users, {
  name: (schema) => schema.atMostLength(20), // Extends schema
  bio: () => type.string.atMostLength(2000), // Extends schema before becoming nullable/optional
  preferences: type({ theme: 'string' }) // Overwrites the field, including its nullability
});

const parsed: ArkErrors | {
  id: number;
  name: string,
  bio: string | null;
  preferences: {
    theme: string;
  };
} = userSelectSchema(...);
```

### Data type reference

MSSQL data type mappings follow the MSSQL column builders. See the [MSSQL data types](/docs/mssql/column-types) page for the full column reference.


Source: https://orm.drizzle.team/docs/mssql/cache

import Callout from '@mdx/Callout.astro';
import Npm from '@mdx/Npm.astro';

# Cache

Drizzle sends every query straight to your database by default. There are no hidden actions, no automatic caching 
or invalidation - you'll always see exactly what runs. If you want caching, you must opt in.

By default, Drizzle uses a `explicit` caching strategy (i.e. `global: false`), so nothing is ever cached unless you ask. 
This prevents surprises or hidden performance traps in your application. 
Alternatively, you can flip on `all` caching (`global: true`) so that every select will look in cache first.

## Quickstart

### Upstash integration

Drizzle provides an `upstashCache()` helper out of the box. By default, this uses Upstash Redis with automatic configuration if environment variables are set.

```ts
import { upstashCache } from "drizzle-orm/cache/upstash";
import { drizzle } from "drizzle-orm/node-mssql";

const db = drizzle(process.env.DB_URL!, {
  cache: upstashCache({ token: process.env.UPSTASH_TOKEN, url: process.env.UPSTASH_URL }),
});
```

You can also explicitly define your Upstash credentials, enable global caching for all queries by default or pass custom caching options:

```ts
import { upstashCache } from "drizzle-orm/cache/upstash";
import { drizzle } from "drizzle-orm/node-mssql";

const db = drizzle(process.env.DB_URL!, {
  cache: upstashCache({
    // 👇 Redis credentials (optional — can also be pulled from env vars)
    url: '<UPSTASH_URL>',
    token: '<UPSTASH_TOKEN>',

    // 👇 Enable caching for all queries by default (optional)
    global: true,

    // 👇 Default cache behavior (optional)
    config: { ex: 60 }
  })
});
```

## Cache config reference

Drizzle supports the following cache config options for Upstash:

```ts
export type CacheConfig = {
  /**
   * Expiration in seconds (positive integer)
   */
  ex?: number;
  /**
   * Set an expiration (TTL or time to live) on one or more fields of a given hash key.
   * Used for HEXPIRE command
   */
  hexOptions?: "NX" | "nx" | "XX" | "xx" | "GT" | "gt" | "LT" | "lt";
};
```

## Cache usage examples

Once you've configured caching, here's how the cache behaves:

**Case 1: Drizzle with `global: false` (default, opt-in caching)**

```ts
import { upstashCache } from "drizzle-orm/cache/upstash";
import { drizzle } from "drizzle-orm/node-mssql";

const db = drizzle(process.env.DB_URL!, {
  // 👇 `global: true` is not passed, false by default
  cache: upstashCache({ url: "", token: "" }),
});
```

In this case, the following query won't read from cache

```ts
const res = await db.select().from(users);

// Any mutate operation will still trigger the cache's onMutate handler
// and attempt to invalidate any cached queries that involved the affected tables
await db.insert(users).value({ email: "cacheman@upstash.com" });
```

To make this query read from the cache, call `.$withCache()`

```ts
const res = await db.select().from(users).$withCache();
```

`.$withCache` has a set of options you can use to manage and configure this specific query strategy

```ts
// rewrite the config for this specific query
.$withCache({ config: {} })

// give this query a custom cache key (instead of hashing query+params under the hood)
.$withCache({ tag: 'custom_key' })

// turn off auto-invalidation for this query
// note: this leads to eventual consistency (explained below)
.$withCache({ autoInvalidate: false })
```

<Callout>
**Eventual consistency example**

This example is only relevant if you manually set `autoInvalidate: false`. By default, `autoInvalidate` is enabled. 

You might want to turn off `autoInvalidate` if:
- your data doesn't change often, and slight staleness is acceptable (e.g. product listings, blog posts)
- you handle cache invalidation manually

In those cases, turning it off can reduce unnecessary cache invalidation. However, in most cases, we recommend keeping the default enabled.

Example: Imagine you cache the following query on `usersTable` with a 3-second TTL:

``` ts
const recent = await db
  .select().from(usersTable)
  .$withCache({ config: { ex: 3 }, autoInvalidate: false });
```

If someone runs `db.insert(usersTable)...` the cache won't be invalidated immediately. For up to 3 seconds, you'll keep seeing the old data until it eventually becomes consistent.
</Callout>

**Case 2: Drizzle with `global: true` option**

```ts
import { upstashCache } from "drizzle-orm/cache/upstash";
import { drizzle } from "drizzle-orm/node-mssql";

const db = drizzle(process.env.DB_URL!, {
  cache: upstashCache({ url: "", token: "", global: true }),
});
```

In this case, the following query will read from cache

```ts
const res = await db.select().from(users);
```

If you want to disable cache for this specific query, call `.$withCache(false)`

```ts
// disable cache for this query
const res = await db.select().from(users).$withCache(false);
```

You can also use cache instance from a `db` to invalidate specific tables or tags

```ts
// Invalidate all queries that use the `users` table. You can do this with the Drizzle instance.
await db.$cache.invalidate({ tables: users });
// or
await db.$cache.invalidate({ tables: [users, posts] });

// Invalidate all queries that use the `usersTable`. You can do this by using just the table name.
await db.$cache.invalidate({ tables: "usersTable" });
// or
await db.$cache.invalidate({ tables: ["usersTable", "postsTable"] });

// You can also invalidate custom tags defined in any previously executed select queries.
await db.$cache.invalidate({ tags: "custom_key" });
// or
await db.$cache.invalidate({ tags: ["custom_key", "custom_key1"] });
```

## Custom cache

This example shows how to plug in a custom `cache` in Drizzle: you provide functions to fetch data from the cache, store results back into cache, and invalidate entries whenever a mutation runs.

Cache extension provides this set of config options
```ts
export type CacheConfig = {
  /** expire time, in seconds */
  ex?: number;
  /** expire time, in milliseconds */
  px?: number;
  /** Unix time (sec) at which the key will expire */
  exat?: number;
  /** Unix time (ms) at which the key will expire */
  pxat?: number;
  /** retain existing TTL when updating a key */
  keepTtl?: boolean;
  /** options for HEXPIRE (hash-field TTL) */
  hexOptions?: 'NX' | 'XX' | 'GT' | 'LT' | 'nx' | 'xx' | 'gt' | 'lt';
};
```

```ts
const db = drizzle(process.env.DB_URL!, { cache: new TestGlobalCache() });
```

```ts
import Keyv from "keyv";

export class TestGlobalCache extends Cache {
  private globalTtl: number = 1000;
  // This object will be used to store which query keys were used
  // for a specific table, so we can later use it for invalidation.
  private usedTablesPerKey: Record<string, string[]> = {};

  constructor(private kv: Keyv = new Keyv()) {
    super();
  }

  // For the strategy, we have two options:
  // - 'explicit': The cache is used only when .$withCache() is added to a query.
  // - 'all': All queries are cached globally.
  // The default behavior is 'explicit'.
  override strategy(): "explicit" | "all" {
    return "all";
  }

  // This function accepts query and parameters that cached into key param,
  // allowing you to retrieve response values for this query from the cache.
  override async get(key: string): Promise<any[] | undefined> {
    const res = (await this.kv.get(key)) ?? undefined;
    return res;
  }

  // This function accepts several options to define how cached data will be stored:
  // - 'key': A hashed query and parameters.
  // - 'response': An array of values returned by Drizzle from the database.
  // - 'tables': An array of tables involved in the select queries. This information is needed for cache invalidation.
  // - 'isTag': A boolean flag indicating whether this cache entry represents a tag-based query.
  //    When true, the entry is associated with a specific tag rather than table-level invalidation,
  //    allowing you to invalidate cached queries by tag name. See the UpstashCache:
  //    https://github.com/drizzle-team/drizzle-orm/blob/beta/drizzle-orm/src/cache/upstash/cache.ts for an example
  //
  // For example, if a query uses the "users" and "posts" tables, you can store this information. Later, when the app executes
  // any mutation statements on these tables, you can remove the corresponding key from the cache.
  // If you're okay with eventual consistency for your queries, you can skip this option.
  override async put(
    key: string,
    response: any,
    tables: string[],
    isTag: boolean = false,
    config?: CacheConfig,
  ): Promise<void> {
    const ttl = config?.px ?? (config?.ex ? config.ex * 1000 : this.globalTtl);

    await this.kv.set(key, response, ttl);

    for (const table of tables) {
      const keys = this.usedTablesPerKey[table];
      if (keys === undefined) {
        this.usedTablesPerKey[table] = [key];
      } else {
        keys.push(key);
      }
    }
  }

  // This function is called when insert, update, or delete statements are executed.
  // You can either skip this step or invalidate queries that used the affected tables.
  //
  // The function receives an object with two keys:
  // - 'tags': Used for queries labeled with a specific tag, allowing you to invalidate by that tag.
  // - 'tables': The actual tables affected by the insert, update, or delete statements,
  //   helping you track which tables have changed since the last cache update.
  override async onMutate(params: {
    tags: string | string[];
    tables: string | string[] | Table<any> | Table<any>[];
  }): Promise<void> {
    const tagsArray = params.tags
      ? Array.isArray(params.tags)
        ? params.tags
        : [params.tags]
      : [];
    const tablesArray = params.tables
      ? Array.isArray(params.tables)
        ? params.tables
        : [params.tables]
      : [];

    const keysToDelete = new Set<string>();

    for (const table of tablesArray) {
      const tableName = is(table, Table)
        ? getTableName(table)
        : (table as string);
      const keys = this.usedTablesPerKey[tableName] ?? [];
      for (const key of keys) keysToDelete.add(key);
    }

    if (keysToDelete.size > 0 || tagsArray.length > 0) {
      for (const tag of tagsArray) {
        await this.kv.delete(tag);
      }

      for (const key of keysToDelete) {
        await this.kv.delete(key);
        for (const table of tablesArray) {
          const tableName = is(table, Table)
            ? getTableName(table)
            : (table as string);
          this.usedTablesPerKey[tableName] = [];
        }
      }
    }
  }
}
```

## Limitations

#### Queries that won't be handled by the `cache` extension:

- Using cache with raw queries, such as:

```ts
db.execute(sql`select 1`);
```

```
- Using cache in transactions
```ts
await db.transaction(async (tx) => {
  await tx.update(accounts).set(...).where(...);
  await tx.update...
});
```

#### Limitations that are temporary and will be handled soon:

- Using cache with Drizzle Relational Queries
```ts
await db.query.users.findMany();
```

- Using cache with views


Source: https://orm.drizzle.team/docs/mssql/column-types


import Section from '@mdx/Section.astro';
import Callout from '@mdx/Callout.astro';
import Npm from '@mdx/Npm.astro';

<Npm>
 drizzle-orm@rc
 drizzle-kit@rc -D
</Npm>

<br/>

We have native support for all of them, yet if that's not enough for you, feel free to create **[custom types](/docs/mssql/custom-types)**.

<Callout title='important' type='warning'>
All examples in this part of the documentation do not use database column name aliases, and column names are generated from TypeScript keys. 

You can use database aliases in column names if you want, and you can also use the `casing API` to define a mapping strategy for Drizzle.

You can read more about it [here](/docs/mssql/sql-schema-declaration#shape-your-data-schema)
</Callout>

### int
Signed 4-byte int     

<Section>
```typescript
import { int, mssqlTable } from "drizzle-orm/mssql-core";

export const table = mssqlTable('table', {
	int: int()
});

```

```sql
CREATE TABLE [table] (
	[int] int
);
```
</Section>

<Section>
```typescript
import { int, mssqlTable } from "drizzle-orm/mssql-core";

export const table = mssqlTable('table', {
	int1: int().default(10),
});

```

```sql
CREATE TABLE [table] (
	[int1] int CONSTRAINT [table_int1_default] DEFAULT ((10))
);
```
</Section>

### smallint
`smallint`

Small-range signed 2-byte int   

<Section>
```typescript
import { smallint, mssqlTable } from "drizzle-orm/mssql-core";

export const table = mssqlTable('table', {
	smallint: smallint()
});
```

```sql
CREATE TABLE [table] (
	[smallint] smallint
);
```
</Section>

<Section>
```typescript
import { smallint, mssqlTable } from "drizzle-orm/mssql-core";

export const table = mssqlTable('table', {
	smallint1: smallint().default(10),
});
```

```sql
CREATE TABLE [table] (
	[smallint1] smallint CONSTRAINT [table_smallint1_default] DEFAULT ((10))
);
```
</Section>

### tinyint
`tinyint`

Small-range signed 1-byte int   

<Section>
```typescript
import { tinyint, mssqlTable } from "drizzle-orm/mssql-core";

export const table = mssqlTable('table', {
	tinyint: tinyint()
});
```

```sql
CREATE TABLE [table] (
	[tinyint] tinyint
);
```
</Section>

<Section>
```typescript
import { tinyint, mssqlTable } from "drizzle-orm/mssql-core";

export const table = mssqlTable('table', {
	tinyint1: tinyint().default(10),
});
```

```sql
CREATE TABLE [table] (
	[tinyint1] tinyint CONSTRAINT [table_tinyint1_default] DEFAULT ((10))
);
```
</Section>

### bigint
`bigint`

Signed 8-byte int  

If you're expecting values above 2^31 but below 2^53, you can utilise `mode: 'number'` and deal with javascript number as opposed to bigint.
<Section>
```typescript
import { bigint, mssqlTable } from "drizzle-orm/mssql-core";

export const table = mssqlTable('table', {
	bigint: bigint({ mode: 'number' })
});

// will be inferred as `number`
bigint: bigint({ mode: 'number' })

// will be inferred as `bigint`
bigint: bigint({ mode: 'bigint' })

// will be inferred as `string`
bigint: bigint({ mode: 'string' })
```

```sql
CREATE TABLE [table] (
	[bigint] bigint
);
```
</Section>

<Section>
```typescript
import { bigint, mssqlTable } from "drizzle-orm/mssql-core";

export const table = mssqlTable('table', {
	bigint1: bigint({ mode: 'number' }).default(10)
});
```

```sql
CREATE TABLE [table] (
	[bigint1] bigint CONSTRAINT [table_bigint1_default] DEFAULT ((10))
);
```
</Section>

## ---

### bit

An int data type that can take a value of `1`, `0`, or `NULL`

Drizzle will accept `true` or `false` as values instead of `1` and `0`

<Section>
```typescript
import { bit, mssqlTable } from "drizzle-orm/mssql-core";

export const table = mssqlTable('table', {
	bit: bit()
});

```

```sql
CREATE TABLE [table] (
	[bit] bit
);
```
</Section>

## ---

### text
`text`  
Variable-length non-Unicode data in the code page of the server and with a maximum string length 
of 2^31 - 1 (2,147,483,647)

For more info please refer to the official MSSQL **[docs.](https://learn.microsoft.com/en-us/sql/t-sql/data-types/ntext-text-and-image-transact-sql?view=sql-server-ver17#text)**
  
You can define `{ enum: ["value1", "value2"] }` config to infer `insert` and `select` types, it **won't** check runtime values.
<Section>
```typescript
import { text, mssqlTable } from "drizzle-orm/mssql-core";

export const table = mssqlTable('table', {
  text: text()
});

// will be inferred as text: "value1" | "value2" | null
text: text({ enum: ["value1", "value2"] })
```

```sql
CREATE TABLE [table] (
	[text] text
);
```
</Section>

### ntext
`ntext`  
Variable-length Unicode data with a maximum string length of 2^30 - 1 (1,073,741,823).

For more info please refer to the official MSSQL **[docs.](https://learn.microsoft.com/en-us/sql/t-sql/data-types/ntext-text-and-image-transact-sql?view=sql-server-ver17#ntext)**
  
You can define `{ enum: ["value1", "value2"] }` config to infer `insert` and `select` types, it **won't** check runtime values.
<Section>
```typescript
import { ntext, mssqlTable } from "drizzle-orm/mssql-core";

export const table = mssqlTable('table', {
  ntext: ntext()
});

// will be inferred as text: "value1" | "value2" | null
ntext: ntext({ enum: ["value1", "value2"] })
```

```sql
CREATE TABLE [table] (
	[ntext] ntext
);
```
</Section>

### varchar
`varchar(n|max)`  
Variable-size string data. Use n to define the string size in bytes and can be a value from 1 through 8,000

For more info please refer to the official MSSQL **[docs.](https://learn.microsoft.com/en-us/sql/t-sql/data-types/char-and-varchar-transact-sql?view=sql-server-ver17#varchar---n--max--)**

You can define `{ enum: ["value1", "value2"] }` config to infer `insert` and `select` types, it **won't** check runtime values.

The `length` parameter is optional according to MSSQL docs.
<Section>
```typescript
import { varchar, mssqlTable } from "drizzle-orm/mssql-core";

export const table = mssqlTable('table', {
  varchar1: varchar(),
  varchar2: varchar({ length: 256 }),
  varchar3: varchar({ length: 'max' })
});

// will be inferred as text: "value1" | "value2" | null
varchar: varchar({ enum: ["value1", "value2"] });
```

```sql
CREATE TABLE [table] (
	[varchar1] varchar,
	[varchar2] varchar(256),
	[varchar3] varchar(max)
);
```
</Section>

### nvarchar
`nvarchar(n|max)`  
Variable-size string data. The value of n defines the string size in byte-pairs

For more info please refer to the official MSSQL **[docs.](https://learn.microsoft.com/en-us/sql/t-sql/data-types/nchar-and-nvarchar-transact-sql?view=sql-server-ver17#nvarchar---n--max--)**

You can define `{ enum: ["value1", "value2"] }` config to infer `insert` and `select` types, it **won't** check runtime values.

The `length` parameter is optional according to MSSQL docs.
<Section>
```typescript
import { nvarchar, mssqlTable } from "drizzle-orm/mssql-core";

export const table = mssqlTable('table', {
  nvarchar1: nvarchar(),
  nvarchar2: nvarchar({ length: 256 }),
});

// will be inferred as text: "value1" | "value2" | null
nvarchar: nvarchar({ enum: ["value1", "value2"] });

// will be inferred as `json`
nvarchar: nvarchar({ mode: 'json' })
```

```sql
CREATE TABLE [table] (
	[nvarchar1] nvarchar,
	[nvarchar2] nvarchar(256)
);
```
</Section>

### char
`char(n)`  

Fixed-size string data. n defines the string size in bytes and must be a value from 1 through 8,000

For more info please refer to the official MSSQL **[docs.](https://learn.microsoft.com/en-us/sql/t-sql/data-types/char-and-varchar-transact-sql?view=sql-server-ver17#char---n--)**

You can define `{ enum: ["value1", "value2"] }` config to infer `insert` and `select` types, it **won't** check runtime values.

The `length` parameter is optional according to MSSQL docs.
<Section>
```typescript
import { char, mssqlTable } from "drizzle-orm/mssql-core";

export const table = mssqlTable('table', {
  char1: char(),
  char2: char({ length: 256 }),
});

// will be inferred as text: "value1" | "value2" | null
char: char({ enum: ["value1", "value2"] });
```

```sql
CREATE TABLE [table] (
	[char1] char(1),
	[char2] char(256)
);
```
</Section>

### nchar
`nchar(n)`  

Fixed-size string data. n defines the string size in byte-pairs, and must be a value from 1 through 4,000

For more info please refer to the official MSSQL **[docs.](https://learn.microsoft.com/en-us/sql/t-sql/data-types/nchar-and-nvarchar-transact-sql?view=sql-server-ver17#nchar---n--)**

You can define `{ enum: ["value1", "value2"] }` config to infer `insert` and `select` types, it **won't** check runtime values.

The `length` parameter is optional according to MSSQL docs.
<Section>
```typescript
import { nchar, mssqlTable } from "drizzle-orm/mssql-core";

export const table = mssqlTable('table', {
  nchar1: nchar(),
  nchar2: nchar({ length: 256 }),
});

// will be inferred as text: "value1" | "value2" | null
nchar: nchar({ enum: ["value1", "value2"] });
```

```sql
CREATE TABLE [table] (
	[nchar1] nchar(1),
	[nchar2] nchar(256)
);
```
</Section>

## ---

### binary

Fixed-length binary data with a length of n bytes, where n is a value from 1 through 8,000. The storage size is n bytes.

<Section>
```typescript
import { binary, mssqlTable } from "drizzle-orm/mssql-core";

export const table = mssqlTable('table', {
	binary: binary(),
	binary1: binary({ length: 256 })
});
```

```sql
CREATE TABLE [table] (
	[binary] binary,
	[binary1] binary(256)
);
```
</Section>

### varbinary

Variable-length binary data. n can be a value from 1 through 8,000. max indicates that the maximum storage size is 2^31-1 bytes

<Section>
```typescript
import { varbinary, mssqlTable } from "drizzle-orm/mssql-core";

export const table = mssqlTable('table', {
	varbinary: varbinary(),
	varbinary1: varbinary({ length: 256 }),
	varbinary2: varbinary({ length: 'max' })
});
```

```sql
CREATE TABLE [table] (
	[varbinary] varbinary,
	[varbinary1] varbinary(256),
	[varbinary2] varbinary(max)
);
```
</Section>

## ---

### numeric
`numeric`

Fixed precision and scale numbers. When maximum precision is used, valid values are from -10^38 + 1 through 10^38 - 1

For more info please refer to the official MSSQL **[docs.](https://learn.microsoft.com/en-us/sql/t-sql/data-types/decimal-and-numeric-transact-sql?view=sql-server-ver17#decimal---p---s----and-numeric---p---s---)**

<Section>
```typescript
import { numeric, mssqlTable } from "drizzle-orm/mssql-core";

export const table = mssqlTable('table', {
  numeric1: numeric(),
  numeric2: numeric({ precision: 100 }),
  numeric3: numeric({ precision: 100, scale: 20 })
//   numericNum: numeric({ mode: 'number' }),
//   numericBig: numeric({ mode: 'bigint' }),
});
```

```sql
CREATE TABLE [table] (
	[numeric1] numeric,
	[numeric2] numeric(100),
	[numeric3] numeric(100, 20)
);
```
</Section>

### decimal
An alias of **[numeric.](#numeric)**

### real

The ISO synonym for real is float(24).

For more info please refer to the official MSSQL **[docs.](https://learn.microsoft.com/en-us/sql/t-sql/data-types/float-and-real-transact-sql?view=sql-server-ver17)**  

<Section>
```typescript
import { real, mssqlTable } from "drizzle-orm/mssql-core";  

export const table = mssqlTable('table', {
	real1: real(),
	real2: real().default(10.10)
});
```

```sql
CREATE TABLE [table] (
	[real1] real,
	[real2] real CONSTRAINT [table_real2_default] DEFAULT ((10.1))
);
```
</Section>

### float

float [ (n) ] Where n is the number of bits that are used to store the mantissa of the float number in scientific notation and, therefore, dictates the precision and storage size. If n is specified, it must be a value between 1 and 53. The default value of n is 53.

For more info please refer to the official MSSQL **[docs.](https://learn.microsoft.com/en-us/sql/t-sql/data-types/float-and-real-transact-sql?view=sql-server-ver17#syntax)**  

<Section>
```typescript
import { float, mssqlTable } from "drizzle-orm/mssql-core";

export const table = mssqlTable('table', {
	float1: float(),
	float2: float({ precision: 16 })
});
```

```sql
CREATE TABLE [table] (
	[float1] float,
	[float2] float(16)
);
```
</Section>

## ---

### time
`time`

Defines a time of a day. The time is without time zone awareness and is based on a 24-hour clock.

For more info please refer to the official MSSQL **[docs.](https://learn.microsoft.com/en-us/sql/t-sql/data-types/time-transact-sql?view=sql-server-ver17#time-description)**

<Section>
```typescript
import { time, mssqlTable } from "drizzle-orm/mssql-core";

export const table = mssqlTable('table', {
  time1: time(),
  time2: time({ mode: 'string' }),
  time3: time({ precision: 6 }),
  time4: time({ precision: 6, mode: 'date' })
});
```

```sql
CREATE TABLE [table] (
	[time1] time,
	[time2] time,
	[time3] time(6),
	[time4] time(6)
);
```
</Section>

### date
`date`  

Calendar date (year, month, day)

For more info please refer to the official MSSQL **[docs.](https://learn.microsoft.com/en-us/sql/t-sql/data-types/date-transact-sql?view=sql-server-ver17#date-description)**
<Section>
```typescript
import { date, mssqlTable } from "drizzle-orm/mssql-core";

export const table = mssqlTable('table', {
	date: date(),
});
```

```sql
CREATE TABLE [table] (
	[date] date
);
```
</Section>
You can specify either `date` or `string` infer modes:
```typescript
// will infer as date
date: date({ mode: "date" }),

// will infer as string
date: date({ mode: "string" }),
```

### datetime
`datetime`  

Defines a date that is combined with a time of day with fractional seconds that is based on a 24-hour clock.

<Callout title='MSSQL docs'>
Avoid using datetime for new work. Instead, use the time, date, datetime2, and datetimeoffset data types. These types align with the SQL Standard, and are more portable. time, datetime2 and datetimeoffset provide more seconds precision. datetimeoffset provides time zone support for globally deployed applications.
</Callout>

For more info please refer to the official MSSQL **[docs.](https://learn.microsoft.com/en-us/sql/t-sql/data-types/datetime-transact-sql?view=sql-server-ver17#description)**
<Section>
```typescript
import { datetime, mssqlTable } from "drizzle-orm/mssql-core";

export const table = mssqlTable('table', {
	datetime: datetime(),
});
```

```sql
CREATE TABLE [table] (
	[datetime] datetime
);
```
</Section>
You can specify either `date` or `string` infer modes:
```typescript
// will infer as date
datetime: datetime({ mode: "date" }),

// will infer as string
datetime: datetime({ mode: "string" }),
```

### datetime2
`datetime2`  

Defines a date that is combined with a time of day that is based on 24-hour clock. datetime2 can be considered as an extension of the existing datetime type that has a larger date range, a larger default fractional precision, and optional user-specified precision.

For more info please refer to the official MSSQL **[docs.](https://learn.microsoft.com/en-us/sql/t-sql/data-types/datetime2-transact-sql?view=sql-server-ver17#datetime2-description)**
<Section>
```typescript
import { datetime2, mssqlTable } from "drizzle-orm/mssql-core";

export const table = mssqlTable('table', {
	datetime2: datetime2(),
});
```

```sql
CREATE TABLE [table] (
	[datetime2] datetime2
);
```
</Section>
You can specify either `date` or `string` infer modes:
```typescript
// will infer as date
datetime2: datetime2({ mode: "date" }),

// will infer as string
datetime2: datetime2({ mode: "string" }),
```

### datetimeoffset
`datetimeoffset`  

Defines a date that is combined with a time of a day based on a 24-hour clock like datetime2, and adds time zone awareness based on Coordinated Universal Time (UTC).

For more info please refer to the official MSSQL **[docs.](https://learn.microsoft.com/en-us/sql/t-sql/data-types/datetimeoffset-transact-sql?view=sql-server-ver17#datetimeoffset-description)**
<Section>
```typescript
import { datetimeoffset, mssqlTable } from "drizzle-orm/mssql-core";

export const table = mssqlTable('table', {
	datetimeoffset: datetimeoffset(),
});
```

```sql
CREATE TABLE [table] (
	[datetimeoffset] datetimeoffset
);
```
</Section>
You can specify either `date` or `string` infer modes:
```typescript
// will infer as date
datetimeoffset: datetimeoffset({ mode: "date" }),

// will infer as string
datetimeoffset: datetimeoffset({ mode: "string" }),
```

## ---

### Customizing data type
Every column builder has a `.$type()` method, which allows you to customize the data type of the column. 

This is useful, for example, with unknown or branded types:
```ts
type UserId = number & { __brand: 'user_id' };

export const users = mssqlTable('users', {
  id: int().$type<UserId>().primaryKey(),
});
```

### Default value
The `DEFAULT` clause specifies a default value to use for the column if no value
is explicitly provided by the user when doing an `INSERT`.
If there is no explicit `DEFAULT` clause attached to a column definition,
then the default value of the column is `NULL`.

An explicit `DEFAULT` clause may specify that the default value is `NULL`

<Section>
```typescript
import { int, mssqlTable, text } from "drizzle-orm/mssql-core";

export const table = mssqlTable('table', {
	int: int().default(42),
	text: text().default('text'),
});
```

```sql
CREATE TABLE [table] (
	[int] int CONSTRAINT [table_int_default] DEFAULT ((42)),
	[text] text CONSTRAINT [table_text_default] DEFAULT ('text')
);
```
</Section>

When using `$default()` or `$defaultFn()`, which are simply different aliases for the same function, 
you can generate defaults at runtime and use these values in all insert queries. 

<Callout type="info" emoji="ℹ️">
	Note: This value does not affect the `drizzle-kit` behavior, it is only used at runtime in `drizzle-orm`
</Callout>

```ts
import { text, mssqlTable } from "drizzle-orm/mssql-core";
import { createId } from '@paralleldrive/cuid2';

export const table = mssqlTable('table', {
	id: text().$defaultFn(() => createId()),
});
```

When using `$onUpdate()` or `$onUpdateFn()`, which are simply different aliases for the same function, 
you can generate defaults at runtime and use these values in all update queries. 

Adds a dynamic update value to the column. The function will be called when the row is updated, 
and the returned value will be used as the column value if none is provided.
If no default (or $defaultFn) value is provided, the function will be called
when the row is inserted as well, and the returned value will be used as the column value.

<Callout type="info" emoji="ℹ️">
	Note: This value does not affect the `drizzle-kit` behavior, it is only used at runtime in `drizzle-orm`
</Callout>

```ts
import { int, datetime2, text, mssqlTable } from "drizzle-orm/mssql-core";
import { SQL, sql } from 'drizzle-orm';

export const table = mssqlTable('table', {
	updateCounter: int().default(sql`1`).$onUpdateFn((): SQL => sql`${table.updateCounter} + 1`),
	updatedAt: datetime2({ mode: 'date', precision: 3 }).$onUpdate(() => new Date()),
	alwaysNull: text().$type<string | null>().$onUpdate(() => null),
});
```


### Not null
`NOT NULL` constraint dictates that the associated column may not contain a `NULL` value.

<Section>
```typescript
import { int, mssqlTable } from "drizzle-orm/mssql-core";

export const table = mssqlTable('table', {
	int: int().notNull(),
});
```

```sql
CREATE TABLE [table] (
	[int] int NOT NULL
);
```
</Section>


### Primary key
A primary key constraint indicates that a column, or group of columns, can be used as a unique identifier for rows in the table. 
This requires that the values be both unique and not null.
<Section>
```typescript
import { int, mssqlTable } from "drizzle-orm/mssql-core";

export const table = mssqlTable('table', {
	id: int().primaryKey(),
});
```

```sql
CREATE TABLE [table] (
	[id] int,
	CONSTRAINT [table_pkey] PRIMARY KEY([id])
);
```
</Section>


Source: https://orm.drizzle.team/docs/mssql/connect-overview

# Database connection with Drizzle

Use these MSSQL drivers and providers with Drizzle ORM.

## MSSQL connection docs

- [MSSQL](/docs/mssql/get-started-mssql)


Source: https://orm.drizzle.team/docs/mssql/custom-types

# Custom types

Custom types let you define your own column types with custom SQL data types and JS/DB value transforms

MSSQL exposes `customType` from `drizzle-orm/mysql-core`.

## Examples
The best way to see how `customType` definition is working is to check how existing data types could be defined using `customType` function from Drizzle ORM.

#### Int

```ts
import { customType, mssqlTable } from "drizzle-orm/mssql-core";

const customInt = customType<{ data: number }>({
  dataType() {
    return "int";
  },
});

export const users = mssqlTable("users", {
  id: customInt(),
});
```

#### Text
```ts
import { customType, mssqlTable } from 'drizzle-orm/mssql-core';

const customText = customType<{ data: string }>({
  dataType() {
    return 'text';
  },
});

export const users = mssqlTable("users", {
  name: customText(),
});
```

#### Datetime2
```ts
import { customType, mssqlTable } from "drizzle-orm/mssql-core";

const customTimestamp = customType<{
  data: Date;
  driverData: string;
  config: { precision?: number };
  configRequired: true;
}>({
  dataType(config) {
    const precision = typeof config.precision !== "undefined" ? ` (${config.precision})` : "";
    return `datetime2${precision}`;
  },
  fromDriver(value: string): Date {
    return new Date(value);
  },
});

export const users = mssqlTable("users", {
  createdAt: customTimestamp("created_at", { precision: 4 }),
});
```

Usage for all types will be same as defined functions in Drizzle ORM. For example:
```ts
const usersTable = mssqlTable("users", {
  id: customInt().primaryKey(),
  name: customText().notNull(),
  createdAt: customTimestamp("created_at", { precision: 4 })
    .notNull()
});
```

### TS-doc for type definitions

You can check `ts-doc` for types, param definition and examples

```ts
export type CustomTypeValues = {
	/**
	 * Required type for custom column, that will infer proper type model
	 *
	 * Examples:
	 *
	 * If you want your column to be `string` type after selecting/or on inserting - use `data: string`. Like `text`, `varchar`
	 *
	 * If you want your column to be `number` type after selecting/or on inserting - use `data: number`. Like `integer`
	 */
	data: unknown;

	/**
	 * Type helper, that represents what type database driver is returning for specific database data type
	 *
	 * Needed only in case driver's output and input for type differ
	 *
	 * Defaults to {@link driverData}
	 */
	driverOutput?: unknown;

	/**
	 * Type helper, that represents what type database driver is accepting for specific database data type
	 */
	driverData?: unknown;

	/**
	 * Type helper, that represents what type field returns after being aggregated to JSON
	 */
	jsonData?: unknown;

	/**
	 * What config type should be used for {@link CustomTypeParams} `dataType` generation
	 */
	config?: Record<string, any>;

	/**
	 * Whether the config argument should be required or not
	 * @default false
	 */
	configRequired?: boolean;

	/**
	 * If your custom data type should be notNull by default you can use `notNull: true`
	 *
	 * @example
	 * const customSerial = customType<{ data: number, notNull: true, default: true }>({
	 * 	  dataType() {
	 * 	    return 'serial';
	 *    },
	 * });
	 */
	notNull?: boolean;

	/**
	 * If your custom data type has default you can use `default: true`
	 *
	 * @example
	 * const customSerial = customType<{ data: number, notNull: true, default: true }>({
	 * 	  dataType() {
	 * 	    return 'serial';
	 *    },
	 * });
	 */
	default?: boolean;
};
export interface CustomTypeParams<T extends CustomTypeValues> {
	/**
	 * Database data type string representation, that is used for migrations
	 * @example
	 * ```
	 * `jsonb`, `text`
	 * ```
	 *
	 * If database data type needs additional params you can use them from `config` param
	 * @example
	 * ```
	 * `varchar(256)`, `numeric(2,3)`
	 * ```
	 *
	 * To make `config` be of specific type please use config generic in {@link CustomTypeValues}
	 *
	 * @example
	 * Usage example
	 * ```
	 *   dataType() {
	 *     return 'boolean';
	 *   },
	 * ```
	 * Or
	 * ```
	 *   dataType(config) {
	 * 	   return typeof config.length !== 'undefined' ? `varchar(${config.length})` : `varchar`;
	 * 	 }
	 * ```
	 */
	dataType: (config: T['config'] | (Equal<T['configRequired'], true> extends true ? never : undefined)) => string;

	/**
	 * Optional mapping function, that is used to transform inputs from desired to be used in code format to one suitable for driver
	 * @example
	 * For example, when using jsonb we need to map JS/TS object to string before writing to database
	 * ```
	 * toDriver(value: TData): string {
	 * 	 return JSON.stringify(value);
	 * }
	 * ```
	 */
	toDriver?: (value: T['data']) => T['driverData'] | SQL;

	/**
	 * Optional mapping function, that is used for transforming data returned by driver to desired column's output format
	 * @example
	 * For example, when using timestamp we need to map string Date representation to JS Date
	 * ```
	 * fromDriver(value: string): Date {
	 * 	return new Date(value);
	 * }
	 * ```
	 *
	 * It'll cause the returned data to change from:
	 * ```
	 * {
	 * 	customField: "2025-04-07 03:25:16.635";
	 * }
	 * ```
	 * to:
	 * ```
	 * {
	 * 	customField: new Date("2025-04-07 03:25:16.635");
	 * }
	 * ```
	 */
	fromDriver?: (value: 'driverOutput' extends keyof T ? T['driverOutput'] : T['driverData']) => T['data'];

	/**
	 * Optional mapping function, that is used for transforming data returned by transofmed to JSON in database data to desired format
	 *
	 * Used by [relational queries](https://orm.drizzle.team/docs/rqb)
	 *
	 * Defaults to {@link fromDriver} function
	 * @example
	 * For example, when querying bigint column via [RQB](https://orm.drizzle.team/docs/rqb) or [JSON functions](https://orm.drizzle.team/docs/json-functions), the result field will be returned as it's string representation, as opposed to bigint from regular query
	 * To handle that, we need a separate function to handle such field's mapping:
	 * ```
	 * fromJson(value: string): bigint {
	 * 	return BigInt(value);
	 * },
	 * ```
	 *
	 * It'll cause the returned data to change from:
	 * ```
	 * {
	 * 	customField: "5044565289845416380";
	 * }
	 * ```
	 * to:
	 * ```
	 * {
	 * 	customField: 5044565289845416380n;
	 * }
	 * ```
	 */
	fromJson?: (value: T['jsonData']) => T['data'];

	/**
	 * Optional selection modifier function, that is used for modifying selection of column inside [JSON functions](https://orm.drizzle.team/docs/json-functions)
	 *
	 * Additional mapping that could be required for such scenarios can be handled using {@link fromJson} function
	 *
	 * Used by [relational queries](https://orm.drizzle.team/docs/rqb)
	 *
	 * Following types are being casted to text by default: `binary`, `varbinary`, `time`, `datetime`, `decimal`, `float`, `bigint`
	 * @example
	 * For example, when using bigint we need to cast field to text to preserve data integrity
	 * ```
	 * forJsonSelect(identifier: SQL, sql: SQLGenerator): SQL {
	 * 	return sql`cast(${identifier} as char)`
	 * },
	 * ```
	 *
	 * This will change query from:
	 * ```
	 * SELECT
	 * 	json_build_object('bigint', `t`.`bigint`)
	 * 	FROM
	 * 	(
	 * 		SELECT
	 * 		`table`.`custom_bigint` AS `bigint`
	 * 		FROM
	 * 		`table`
	 * 	) AS `t`
	 * ```
	 * to:
	 * ```
	 * SELECT
	 * 	json_build_object('bigint', `t`.`bigint`)
	 * 	FROM
	 * 	(
	 * 		SELECT
	 * 		cast(`table`.`custom_bigint` as char) AS `bigint`
	 * 		FROM
	 * 		`table`
	 * 	) AS `t`
	 * ```
	 *
	 * Returned by query object will change from:
	 * ```
	 * {
	 * 	bigint: 5044565289845416000; // Partial data loss due to direct conversion to JSON format
	 * }
	 * ```
	 * to:
	 * ```
	 * {
	 * 	bigint: "5044565289845416380"; // Data is preserved due to conversion of field to text before JSON-ification
	 * }
	 * ```
	 */
	forJsonSelect?: (identifier: SQL, sql: SQLGenerator) => SQL;
}
```

Source: https://orm.drizzle.team/docs/mssql/data-querying

import Callout from '@mdx/Callout.astro';
import CodeTabs from "@mdx/CodeTabs.astro";
import Section from '@mdx/Section.astro';
import Flex from "@mdx/Flex.astro"
import LinksList from "@mdx/LinksList.astro"
import Prerequisites from "@mdx/Prerequisites.astro";

# Drizzle Queries + CRUD

<Prerequisites>
  - How to define your schema - [Schema Fundamentals](/docs/mssql/sql-schema-declaration)
  - How to connect to the database - [Connection Fundamentals](/docs/mssql/connect-overview)
</Prerequisites>

Drizzle gives you a few ways for querying your database and it's up to you to decide which one you'll need in your next project.
It can be either SQL-like syntax or Relational Syntax. Let's check them:

## Why SQL-like?

**If you know SQL, you know Drizzle.**

Other ORMs and data frameworks tend to deviate from or abstract away SQL, leading to a double learning curve: you need to learn both SQL and the framework's API.

Drizzle is the opposite.
We embrace SQL and built Drizzle to be SQL-like at its core, so you have little to no learning curve and full access to the power of SQL.

<Section>
```typescript copy
// Access your data
await db
  .select()
	.from(posts)
	.leftJoin(comments, eq(posts.id, comments.post_id))
	.where(eq(posts.id, 10))
```
```sql
SELECT *
FROM [posts]
LEFT JOIN [comments] ON [posts].[id] = [comments].[post_id]
WHERE [posts].[id] = 10
```
</Section>

With SQL-like syntax, you can replicate much of what you can do with pure SQL and know 
exactly what Drizzle will do and what query will be generated. You can perform a wide range of queries, 
including select, insert, update, delete, as well as using aliases, WITH clauses, subqueries, prepared statements, 
and more. Let's look at more examples

<CodeTabs items={['insert', 'update', 'delete']}>
<Section>
```ts
await db.insert(users).values({ email: 'user@gmail.com' })
```
```sql
INSERT INTO [users] ([email]) VALUES ('user@gmail.com')
```
</Section>
<Section>
```ts
await db.update(users)
        .set({ email: 'user@gmail.com' })
        .where(eq(users.id, 1))
```
```sql
UPDATE [users]
SET [email] = 'user@gmail.com'
WHERE [users].[id] = 1
```
</Section>
<Section>
```ts
await db.delete(users).where(eq(users.id, 1))
```
```sql
DELETE FROM [users] WHERE [users].[id] = 1
```
</Section>
</CodeTabs>

## Why not SQL-like?

We're always striving for a perfectly balanced solution. While SQL-like queries cover 100% of your needs, 
there are certain common scenarios where data can be queried more efficiently.

We've built the Queries API so you can fetch relational, nested data from the database in the most convenient 
and performant way, without worrying about joins or data mapping.

**Drizzle always outputs exactly one SQL query**. Feel free to use it with serverless databases,
and never worry about performance or roundtrip costs!

<Section>
```ts
const result = await db._query.users.findMany({
	with: {
		posts: true
	},
});
```
{/* ```sql
SELECT * FROM users ...
``` */}
</Section>

## Advanced
With Drizzle, queries can be composed and partitioned in any way you want. You can compose filters 
independently from the main query, separate subqueries or conditional statements, and much more. 
Let's check a few advanced examples:

#### Compose a WHERE statement and then use it in a query
```ts
async function getProductsBy({
  name,
  category,
  maxPrice,
}: {
  name?: string;
  category?: string;
  maxPrice?: number;
}) {
  const filters: SQL[] = [];

  if (name) filters.push(like(products.name, name));
  if (category) filters.push(eq(products.category, category));
  if (maxPrice) filters.push(lte(products.price, maxPrice));

  return db
    .select()
    .from(products)
    .where(and(...filters));
}
```

#### Separate subqueries into different variables, and then use them in the main query
```ts
const subquery = db
	.select()
	.from(internalStaff)
	.leftJoin(customUser, eq(internalStaff.userId, customUser.id))
	.as('internal_staff');

const mainQuery = await db
	.select()
	.from(ticket)
	.leftJoin(subquery, eq(subquery.internal_staff.userId, ticket.staffId));
```

#### What's next?
<br/>
<Flex>
  <LinksList 
    title='Access your data'
    links={[
        ["Query", "/docs/mssql/rqb"], 
        ["Select", "/docs/mssql/select"],
        ["Insert", "/docs/mssql/insert"],
        ["Update", "/docs/mssql/update"],
        ["Delete", "/docs/mssql/delete"],
        ["Filters", "/docs/mssql/operators"],
        ["Joins", "/docs/mssql/joins"],
        ["sql`` operator", "/docs/mssql/sql"],
      ]}
  />
  <LinksList 
    title='Zero to Hero'
    links={[
        ["Migrations", "/docs/mssql/migrations"], 
      ]}
  />
</Flex>


Source: https://orm.drizzle.team/docs/mssql/delete

import Callout from '@mdx/Callout.astro';
import Section from '@mdx/Section.astro';

# SQL Delete

You can delete all rows in the table:
```typescript copy
await db.delete(users);
```
And you can delete with filters and conditions:
```typescript copy
await db.delete(users).where(eq(users.name, 'Dan'));
```

### Output

You can delete a row and get it back in PostgreSQL:
```typescript copy
const deletedUser = await db.delete(users)
  .where(eq(users.name, 'Dan'))
  .output();

// partial return
const deletedUserId = await db.delete(users)
  .where(eq(users.name, "Dan"))
  .output({ deletedId: users.id });

// deletedUserId: { deletedId: number }[]
```
```sql
delete from [users] output DELETED.[id], DELETED.[name], DELETED.[age] where [users].[name] = 'Dan'

delete from [users] output DELETED.[id] where [users].[name] = 'Dan'
```

Source: https://orm.drizzle.team/docs/mssql/drizzle-config-file

import CodeTab from "@mdx/CodeTab.astro";
import CodeTabs from "@mdx/CodeTabs.astro";
import Section from "@mdx/Section.astro";
import Tab from "@mdx/Tab.astro";
import Tabs from "@mdx/Tabs.astro";
import Callout from "@mdx/Callout.astro";
import SchemaFilePaths from "@mdx/SchemaFilePaths.mdx"
import Prerequisites from "@mdx/Prerequisites.astro"
import Dialects from "@mdx/Dialects.mdx"
import Drivers from "@mdx/Drivers.mdx"
import DriversExamples from "@mdx/DriversExamples.mdx"
import Npx from "@mdx/Npx.astro"

# Drizzle Kit configuration file
<Prerequisites>
- Get started with Drizzle and `drizzle-kit` - [read here](/docs/mssql/get-started)
- Drizzle schema fundamentals - [read here](/docs/mssql/sql-schema-declaration)
- Database connection basics - [read here](/docs/mssql/connect-overview)
- Drizzle migrations fundamentals - [read here](/docs/mssql/migrations)
- Drizzle Kit [overview](/docs/mssql/kit-overview) and [config file](/docs/mssql/drizzle-config-file)
</Prerequisites>

Drizzle Kit lets you declare configuration options in `TypeScript` or `JavaScript` configuration files.

<Section>
```plaintext {5}
📦 <project root>
 ├ ...
 ├ 📂 drizzle
 ├ 📂 src
 ├ 📜 drizzle.config.ts
 └ 📜 package.json
```
<CodeTabs items={["drizzle.config.ts", "drizzle.config.js"]}>
<CodeTab>
```ts
import { defineConfig } from "drizzle-kit";

export default defineConfig({
  dialect: "mssql",
  schema: "./src/schema.ts",
  out: "./drizzle",
});
```
</CodeTab>
<CodeTab>
```js
import { defineConfig } from "drizzle-kit";

export default defineConfig({
  dialect: "mssql",
  schema: "./src/schema.ts",
  out: "./drizzle",
});
```
</CodeTab>
</CodeTabs>
</Section>

Example of an extended config file
```ts collapsable
import { defineConfig } from "drizzle-kit";

export default defineConfig({
  out: "./drizzle",
  dialect: "mssql",
  schema: "./src/schema.ts",

  dbCredentials: {
    url: "mssql://user:password@host:3306/dbname",
  },

  schemaFilter: "dbo",
  tablesFilter: "*",

  introspect: {
    casing: "camel",
  },

  migrations: {
    table: "__drizzle_migrations__",
    schema: "drizzle",
  },

  breakpoints: true,
  verbose: true,
});
```

### Multiple configuration files
You can have multiple config files in the project, it's very useful when you have multiple database stages or multiple databases or different databases on the same project:
<Npx>
  drizzle-kit generate --config=drizzle-dev.config.ts
  drizzle-kit generate --config=drizzle-prod.config.ts
</Npx>
```plaintext {5-6}
📦 <project root>
 ├ 📂 drizzle
 ├ 📂 src
 ├ 📜 .env
 ├ 📜 drizzle-dev.config.ts
 ├ 📜 drizzle-prod.config.ts
 ├ 📜 package.json
 └ 📜 tsconfig.json
```

### Migrations folder
`out` param lets you define folder for your migrations, it's optional and `drizzle` by default.  
It's very useful since you can have many separate schemas for different databases in the same project 
and have different migration folders for them.  
  
Migration folder contains folders with `.sql` migration files which is used by `drizzle-kit`

<Section>
```plaintext {3}
📦 <project root>
 ├ ...
 ├ 📂 drizzle
 │ ├ 📂 20242409125510_premium_mister_fear
 │ ├ 📜 user.ts 
 │ ├ 📜 post.ts 
 │ └ 📜 comment.ts 
 ├ 📂 src
 ├ 📜 drizzle.config.ts
 └ 📜 package.json
```
```ts {6}
import { defineConfig } from "drizzle-kit";

export default defineConfig({
  dialect: "mssql",
  schema: "./src/schema/*",
  out: "./drizzle",
});
```
</Section>

## ---

### `dialect`
<rem025/>

Dialect of the database you're using 
|               |                                                 |
| :------------ | :-----------------------------------            |
| type        | <Dialects/>                                     |
| default        | --                                     |
| commands    | `generate`, `push`, `pull`, `studio`,  `migrate`, `up`, `export` |

<rem025/>
```ts {4}
import { defineConfig } from "drizzle-kit";

export default defineConfig({
  dialect: "mssql", 
});
```


### `schema`
<rem025/>

[`glob`](https://www.digitalocean.com/community/tools/glob?comments=true&glob=/**/*.js&matches=false&tests=//%20This%20will%20match%20as%20it%20ends%20with%20'.js'&tests=/hello/world.js&tests=//%20This%20won't%20match!&tests=/test/some/globs)
 based path to drizzle schema file(s) or folder(s) contaning schema files.
|               |                      |
| :------------ | :-----------------   |
| type          | `string` `string[]` |
| default        | --                    |
| commands      | `generate`, `push`, `export`, `studio`  |

<rem025/>
<SchemaFilePaths />


### `out`
<rem025/>

Defines output folder of your SQL migration files, json snapshots of your schema and `schema.ts` from `drizzle-kit pull` command.
|               |                      |
| :------------ | :-----------------   |
| type          | `string` `string[]` |
| default        | `drizzle`                    |
| commands      | `generate`, `pull`, `migrate`, `check`, `up` |

<rem025/>
```ts {4}
import { defineConfig } from "drizzle-kit";

export default defineConfig({
  out: "./drizzle", 
});
```

## ---

### `dbCredentials`
<rem025/>

Database connection credentials in a form of `url` or 
`user:password@host:port/db` params.

|               |                      |
| :------------ | :-----------------   |
| type          | <Dialects/> |
| default       | --                    |
| commands      | `push`, `pull`, `migrate`, `studio` |

<rem025/>

<CodeTabs items={["Connection string", "Connection params"]}>
```ts
import { defineConfig } from 'drizzle-kit'

export default defineConfig({
  dialect: "mssql",
  dbCredentials: {
    url: "mssql://user:password@host:3306/db",
  }
});
```
```ts
import { defineConfig } from 'drizzle-kit';

export default defineConfig({
  dialect: 'mssql',
  schema: './schema.ts',
  breakpoints: false,
  dbCredentials: {
    database: '',
    password: '',
    port: 3306,
    server: '',
    user: '',
    options: {
      encrypt: true,
      trustServerCertificate: true,
    },
  },
});
```
</CodeTabs>

### `migrations`
<rem025/>

When running `drizzle-kit migrate` - drizzle will records about 
successfully applied migrations in your database in log table named `__drizzle_migrations` in `drizzle` schema.

`migrations` config options lets you change both migrations log `table` name and `schema`.

|               |                      |
| :------------ | :-----------------   |
| type          | `{ table: string, schema: string }` |
| default       | `{ table: "__drizzle_migrations", schema: "drizzle" }`                    |
| commands      | `migrate`, `push`, `pull` |

<rem025/>

```ts
export default defineConfig({
  dialect: "mssql",
  schema: "./src/schema.ts",
  migrations: {
    table: 'my-migrations-table', // `__drizzle_migrations` by default
    schema: 'my_schema', // `drizzle` by default
  },
});
```

### `introspect`
<rem025/>

Configuration for `drizzle-kit pull` command.

`casing` is responsible for in-code column keys casing

|               |                      |
| :------------ | :-----------------   |
| type          | `{ casing: "preserve" \| "camel" }` |
| default       | `{ casing: "camel" }`                    |
| commands      | `pull`   |

<rem025/>

<CodeTabs items={["camel", "preserve"]}>
<Section>
```ts
import * as p from "drizzle-orm/mssql-core"

export const users = p.mssqlTable("users", {
  id: p.int().primaryKey().identity(),
  firstName: p.varchar("first-name", { length: 255 }),
  lastName: p.varchar("LastName", { length: 255 }),
  email: p.varchar("email", { length: 255 }),
  phoneNumber: p.varchar("phone_number", { length: 255 }),
});
```
```sql
SELECT COLUMN_NAME, DATA_TYPE FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = 'users';
```
``` 
 COLUMN_NAME   | DATA_TYPE        
---------------+--------------
 id            | int
 first-name    | varchar
 LastName      | varchar
 email         | varchar
 phone_number  | varchar
```
</Section>
<Section>
```ts
import * as p from "drizzle-orm/mssql-core"

export const users = p.mssqlTable("users", {
  id: p.int().primaryKey().identity(),
  "first-name": p.varchar("first-name", { length: 255 }),
  LastName: p.varchar("LastName", { length: 255 }),
  email: p.varchar("email", { length: 255 }),
  phone_number: p.varchar("phone_number", { length: 255 }),
});
```
```sql
SELECT COLUMN_NAME, DATA_TYPE FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = 'users';
```
``` 
 COLUMN_NAME   | DATA_TYPE
---------------+--------------
 id            | int
 first-name    | varchar
 LastName      | varchar
 email         | varchar
 phone_number  | varchar
```
</Section>
</CodeTabs>


## --- 

### `tablesFilter`
<Callout>
If you want to run multiple projects with one database - check out [our guide](/docs/mssql/goodies#multi-project-schema).
</Callout>
<rem025/>
`drizzle-kit push` and `drizzle-kit pull` will manage all tables by default.
You can configure list of tables and schemas via `tablesFilters` and `schemaFilter` options.

`tablesFilter` option lets you specify [`glob`](https://www.digitalocean.com/community/tools/glob?comments=true&glob=/**/*.js&matches=false&tests=//%20This%20will%20match%20as%20it%20ends%20with%20'.js'&tests=/hello/world.js&tests=//%20This%20won't%20match!&tests=/test/some/globs) 
based table names filter, e.g. `["users", "user_info"]` or `"user*"`

|               |                      |
| :------------ | :-----------------   |
| type          | `string` `string[]` |
| default       | --                    |
| commands      | `push` `pull`   |

<rem025/>
```ts
import { defineConfig } from "drizzle-kit";

export default defineConfig({
  dialect: "mssql",
  tablesFilter: ["users", "posts", "project1_*"],
});
```

### `schemaFilter`


<Callout>
If you want to run multiple projects with one database - check out [our guide](/docs/mssql/goodies#multi-project-schema).
</Callout>

`drizzle-kit push` and `drizzle-kit pull` will by default manage all schemas.

`schemaFilter` option lets you specify [`glob`](https://www.digitalocean.com/community/tools/glob?comments=true&glob=/**/*.js&matches=false&tests=//%20This%20will%20match%20as%20it%20ends%20with%20'.js'&tests=/hello/world.js&tests=//%20This%20won't%20match!&tests=/test/some/globs) 
based schema names filter, e.g. `["dbo", "auth"]` or `"tenant_*"`

|               |                      |
| :------------ | :-----------------   |
| type          | `string[]` |
| commands      | `push` `pull`   |

<rem025/>

```ts
export default defineConfig({
  dialect: "mssql",
  schemaFilter: ["dbo", "schema1", "schema2"],
});
```

## ---

### `verbose`
<rem025/>

Print all SQL statements during `drizzle-kit push` command.

|               |                      |
| :------------ | :-----------------   |
| type          | `boolean` |
| default       | `false`                    |
| commands      | `pull`   |

<rem025/>

```ts
export default defineConfig({
  dialect: "mssql",
  verbose: false,
});
```

### `breakpoints`
<rem025/>

Drizzle Kit will automatically embed `--> statement-breakpoint` into generated SQL migration files, 
that's necessary for databases that do not support multiple DDL alternation statements in one transaction.

`breakpoints` option flag lets you switch it on and off

|               |                      |
| :------------ | :-----------------   |
| type          | `boolean` |
| default       | `true`                    |
| commands      | `generate` `pull`   |

<rem025/>

```ts
export default defineConfig({
  dialect: "mssql",
  breakpoints: false,
});
```


Source: https://orm.drizzle.team/docs/mssql/drizzle-kit-check

import CodeTab from "@mdx/CodeTab.astro";
import CodeTabs from "@mdx/CodeTabs.astro";
import Section from "@mdx/Section.astro";
import Tab from "@mdx/Tab.astro";
import Tabs from "@mdx/Tabs.astro";
import Callout from "@mdx/Callout.astro";
import Prerequisites from "@mdx/Prerequisites.astro";
import Npm from "@mdx/Npm.astro";
import Npx from "@mdx/Npx.astro";
import Dialects from "@mdx/Dialects.mdx"

# `drizzle-kit check`

<Prerequisites>
- Get started with Drizzle and `drizzle-kit` - [read here](/docs/mssql/get-started)
- Drizzle schema fundamentals - [read here](/docs/mssql/sql-schema-declaration)
- Database connection basics - [read here](/docs/mssql/connect-overview)
- Drizzle migrations fundamentals - [read here](/docs/mssql/migrations)
- Drizzle Kit [overview](/docs/mssql/kit-overview) and [config file](/docs/mssql/drizzle-config-file)
- `drizzle-kit generate` command - [read here](/docs/mssql/drizzle-kit-generate)
</Prerequisites>

`drizzle-kit check` command lets you check consistency of your generated SQL migrations history.

That's extremely useful when you have multiple developers working on the project and 
altering database schema on different branches - read more about [migrations for teams](/docs/mssql/kit-migrations-for-teams).

<br/>
<hr/>
<br/>

`drizzle-kit check` command requires you to specify `dialect`, 
you can provide it either via [drizzle.config.ts](/docs/mssql/drizzle-config-file) config file or via CLI options

<CodeTabs items={["With config file", "As CLI options"]}>
<Section>
```ts {5,8}
// drizzle.config.ts
import { defineConfig } from "drizzle-kit";

export default defineConfig({
  dialect: "mssql",
});
```
```shell
npx drizzle-kit check
```
</Section>
```shell
npx drizzle-kit check --dialect=mssql
```
</CodeTabs>

### Multiple configuration files in one project
You can have multiple config files in the project, it's very useful when you have multiple database stages or multiple databases on the same project:
<Npx>
  drizzle-kit check --config=drizzle-dev.config.ts
  drizzle-kit check --config=drizzle-prod.config.ts
</Npx>
```plaintext {5-6}
📦 <project root>
 ├ 📂 drizzle
 ├ 📂 src
 ├ 📜 .env
 ├ 📜 drizzle-dev.config.ts
 ├ 📜 drizzle-prod.config.ts
 ├ 📜 package.json
 └ 📜 tsconfig.json
```

### Ignore conflicts

In case you need `check` command to skip commutativity checks and bypass it, you can use `--ignore-conflicts`. If there is a situation you want to use it, then
there is a big chance that `drizzle-kit` didn't check migrations right and it's a bug. Please report us your case, so we can fix it

```shell
drizzle-kit check --ignore-conflicts
```

### Extended list of configurations
We recommend configuring `drizzle-kit` through [drizzle.config.ts](/docs/mssql/drizzle-config-file) file, 
yet you can provide all configuration options through CLI if necessary, e.g. in CI/CD pipelines, etc.
<rem025/>
|           |            |                                                                         |
| :-------- | :--------- | :---------------------------------------------------------------------- |
| `dialect` | `required` | Database dialect you are using. Can be one of <Dialects/> |
| `out`     |            | Migrations folder, default=`./drizzle`                                         |
| `config`  |            | Configuration file path, default=`drizzle.config.ts`                           |
<br/>
<Npx>
drizzle-kit check --dialect=mssql
drizzle-kit check --dialect=mssql --out=./migrations-folder
</Npx>


Source: https://orm.drizzle.team/docs/mssql/drizzle-kit-export

import CodeTab from "@mdx/CodeTab.astro";
import CodeTabs from "@mdx/CodeTabs.astro";
import Section from "@mdx/Section.astro";
import Tab from "@mdx/Tab.astro";
import Tabs from "@mdx/Tabs.astro";
import Callout from "@mdx/Callout.astro";
import Prerequisites from "@mdx/Prerequisites.astro"
import Npx from "@mdx/Npx.astro";
import SchemaFilePaths from "@mdx/SchemaFilePaths.mdx"
import Dialects from "@mdx/Dialects.mdx"

# `drizzle-kit export` 

<Prerequisites>
- Get started with Drizzle and `drizzle-kit` - [read here](/docs/mssql/get-started)
- Drizzle schema fundamentals - [read here](/docs/mssql/sql-schema-declaration)
- Database connection basics - [read here](/docs/mssql/connect-overview)
- Drizzle migrations fundamentals - [read here](/docs/mssql/migrations)
- Drizzle Kit [overview](/docs/mssql/kit-overview) and [config file](/docs/mssql/drizzle-config-file)
</Prerequisites>


<br/>

`drizzle-kit export` lets you export SQL representation of Drizzle schema and print in console SQL DDL representation on it.
<Callout collapsed="How it works under the hood?">
Drizzle Kit `export` command triggers a sequence of events:
1. It will read through your Drizzle schema file(s) and compose a json snapshot of your schema
2. Based on the current json snapshot it will generate SQL DDL statements
3. Output SQL DDL statements to console
</Callout>

It's designed to cover [codebase first](/docs/mssql/migrations) approach of managing Drizzle migrations. 
You can export the SQL representation of the Drizzle schema, allowing external tools like Atlas to handle all the migrations for you

`drizzle-kit export` command requires you to provide both `dialect` and `schema` path options, 
you can set them either via [drizzle.config.ts](/docs/mssql/drizzle-config-file) config file or via CLI options
<CodeTabs items={["With config file", "As CLI options"]}>
<Section>
```ts
// drizzle.config.ts
import { defineConfig } from "drizzle-kit";

export default defineConfig({
  dialect: "mssql",
  schema: "./src/schema.ts",
});
```
```shell
npx drizzle-kit export
```
</Section>

```shell
npx drizzle-kit export --dialect=mssql --schema=./src/schema.ts
```
</CodeTabs>

### Schema files path
You can have a single `schema.ts` file or as many schema files as you want spread out across the project. 
Drizzle Kit requires you to specify path(s) to them as a [glob](https://www.digitalocean.com/community/tools/glob?comments=true&glob=/**/*.js&matches=false&tests=//%20This%20will%20match%20as%20it%20ends%20with%20'.js'&tests=/hello/world.js&tests=//%20This%20won't%20match!&tests=/test/some/globs) via `schema` configuration option.

<SchemaFilePaths/>

### Multiple configuration files in one project
You can have multiple config files in the project, it's very useful when you have multiple database stages or multiple databases or different databases on the same project:
<Npx>
  drizzle-kit export --config=drizzle-dev.config.ts
  drizzle-kit export --config=drizzle-prod.config.ts
</Npx>
```plaintext {5-6}
📦 <project root>
 ├ 📂 drizzle
 ├ 📂 src
 ├ 📜 .env
 ├ 📜 drizzle-dev.config.ts
 ├ 📜 drizzle-prod.config.ts
 ├ 📜 package.json
 └ 📜 tsconfig.json
```

### Extended list of available configurations
`drizzle-kit export` has a list of cli-only options

<rem025/>

|               |                                                      |
| :--------     | :--------------------------------------------------- |
| `--sql`       | generating SQL representation of Drizzle Schema               |

By default, Drizzle Kit outputs SQL files, but in the future, we want to support different formats

<rem025/>

<Npx>
drizzle-kit export --sql=true
</Npx>

<br/>
<hr/>
<br/>
We recommend configuring `drizzle-kit` through [drizzle.config.ts](/docs/mssql/drizzle-config-file) file, 
yet you can provide all configuration options through CLI if necessary, e.g. in CI/CD pipelines, etc.

|               |            |                                                                            |
| :------------ | :-------   | :----------------------------------------------------------------------    |
| `dialect`     | `required` | Database dialect, one of <Dialects/>                                       |
| `schema`      | `required` | Path to typescript schema file(s) or folder(s) with multiple schema files  |
| `config`      |            | Configuration file path, default is `drizzle.config.ts`                    |

### Example
Example of how to export drizzle schema to console with Drizzle schema located in `./src/schema.ts`

We will also place drizzle config file in the `configs` folder.

Let's create config file:

```plaintext {4}
📦 <project root>
 ├ 📂 configs
 │ └ 📜 drizzle.config.ts
 ├ 📂 src
 │ └ 📜 schema.ts
 └ …
```
```ts filename='drizzle.config.ts'
import { defineConfig } from "drizzle-kit";

export default defineConfig({
  dialect: "mssql",
  schema: "./src/schema.ts",
});
```

```ts filename='schema.ts'
import { mssqlTable, int, text } from 'drizzle-orm/mssql-core'

export const users = mssqlTable('users', {
	id: int().primaryKey().identity(),
	email: text().notNull(),
	name: text()
});
```

Now let's run
```shell
npx drizzle-kit export --config=./configs/drizzle.config.ts
```
And it will successfully output SQL representation of drizzle schema
```bash
CREATE TABLE [users] (
        [id] int IDENTITY(1, 1),
        [email] text NOT NULL,
        [name] text,
        CONSTRAINT [users_pkey] PRIMARY KEY([id])
);
```

Source: https://orm.drizzle.team/docs/mssql/drizzle-kit-generate

import CodeTab from "@mdx/CodeTab.astro";
import CodeTabs from "@mdx/CodeTabs.astro";
import Section from "@mdx/Section.astro";
import Tab from "@mdx/Tab.astro";
import Tabs from "@mdx/Tabs.astro";
import Callout from "@mdx/Callout.astro";
import Prerequisites from "@mdx/Prerequisites.astro"
import Npx from "@mdx/Npx.astro";
import SchemaFilePaths from "@mdx/SchemaFilePaths.mdx"
import Dialects from "@mdx/Dialects.mdx"

# `drizzle-kit generate` 

<Prerequisites>
- Get started with Drizzle and `drizzle-kit` - [read here](/docs/mssql/get-started)
- Drizzle schema fundamentals - [read here](/docs/mssql/sql-schema-declaration)
- Database connection basics - [read here](/docs/mssql/connect-overview)
- Drizzle migrations fundamentals - [read here](/docs/mssql/migrations)
- Drizzle Kit [overview](/docs/mssql/kit-overview) and [config file](/docs/mssql/drizzle-config-file)
</Prerequisites>


<br/>

`drizzle-kit generate` lets you generate SQL migrations based on your Drizzle schema upon declaration or on subsequent schema changes.
<Callout collapsed="How it works under the hood?">
Drizzle Kit `generate` command triggers a sequence of events:
1. It will read through your Drizzle schema file(s) and compose a json snapshot of your schema
2. It will read through your previous migrations folders and compare current json snapshot to the most recent one
3. Based on json differences it will generate SQL migrations
4. Save `migration.sql` and `snapshot.json` in migration folder under current timestamp

<Section>
```typescript filename="src/schema.ts"
import * as p from "drizzle-orm/mssql-core";

export const users = p.mssqlTable("users", {
  id: p.int().primaryKey().identity(),
  name: p.nvarchar({ length: 255 }),
  email: p.nvarchar({ length: 255 }).unique(), 
});
```
```                                  
┌────────────────────────┐                  
│ $ drizzle-kit generate │                  
└─┬──────────────────────┘                  
  │                                           
  └ 1. read previous migration folders
    2. find diff between current and previous schema
    3. prompt developer for renames if necessary
  ┌ 4. generate SQL migration and persist to file
  │    ┌─┴───────────────────────────────────────┐  
  │      📂 drizzle       
  │      └ 📂 20242409125510_premium_mister_fear
  │        ├ 📜 migration.sql
  │        └ 📜 snapshot.json
  v
```
```sql
-- drizzle/20242409125510_premium_mister_fear/migration.sql

CREATE TABLE [users] (
	[id] int IDENTITY(1, 1),
	[name] nvarchar(255),
	[email] nvarchar(255),
	CONSTRAINT [users_pkey] PRIMARY KEY([id]),
	CONSTRAINT [users_email_key] UNIQUE([email])
);
```
</Section>
</Callout>

It's designed to cover [code first](/docs/mssql/migrations) approach of managing Drizzle migrations. 
You can apply generated migrations using [`drizzle-kit migrate`](/docs/mssql/drizzle-kit-migrate), using drizzle-orm's `migrate()`, 
using external migration tools like [bytebase](https://www.bytebase.com/) or running migrations yourself directly on the database. 

`drizzle-kit generate` command requires you to provide both `dialect` and `schema` path options, 
you can set them either via [drizzle.config.ts](/docs/mssql/drizzle-config-file) config file or via CLI options
<CodeTabs items={["With config file", "As CLI options"]}>
<Section>
```ts
// drizzle.config.ts
import { defineConfig } from "drizzle-kit";

export default defineConfig({
  dialect: "mssql",
  schema: "./src/schema.ts",
});
```
```shell
npx drizzle-kit generate
```
</Section>

```shell
npx drizzle-kit generate --dialect=mssql --schema=./src/schema.ts
```
</CodeTabs>

### Schema files path
You can have a single `schema.ts` file or as many schema files as you want spread out across the project. 
Drizzle Kit requires you to specify path(s) to them as a [glob](https://www.digitalocean.com/community/tools/glob?comments=true&glob=/**/*.js&matches=false&tests=//%20This%20will%20match%20as%20it%20ends%20with%20'.js'&tests=/hello/world.js&tests=//%20This%20won't%20match!&tests=/test/some/globs) via `schema` configuration option.

<SchemaFilePaths/>


### Custom migration file name
You can set custom migration file names by providing `--name` CLI option
```shell
npx drizzle-kit generate --name=init
```
```plaintext {4}
📦 <project root>
 ├ 📂 drizzle
 │ └ 📂 20242409125510_init
 │   ├ 📜 snapshot.json
 │   └ 📜 migration.sql
 ├ 📂 src
 └ …
```

### Multiple configuration files in one project
You can have multiple config files in the project, it's very useful when you have multiple database stages or multiple databases or different databases on the same project:
<Npx>
  drizzle-kit generate --config=drizzle-dev.config.ts
  drizzle-kit generate --config=drizzle-prod.config.ts
</Npx>
```plaintext {5-6}
📦 <project root>
 ├ 📂 drizzle
 ├ 📂 src
 ├ 📜 .env
 ├ 📜 drizzle-dev.config.ts
 ├ 📜 drizzle-prod.config.ts
 ├ 📜 package.json
 └ 📜 tsconfig.json
```

### Custom migrations
You can generate empty migration files to write your own custom SQL migrations 
for DDL alternations currently not supported by Drizzle Kit or data seeding. Extended docs on custom migrations - [see here](/docs/mssql/kit-custom-migrations)

```shell
drizzle-kit generate --custom --name=seed-users
```
<Section>
```plaintext {5}
📦 <project root>
 ├ 📂 drizzle
 │ ├ 📂 20242409125510_init
 │ └ 📂 20242409125510_seed-users
 ├ 📂 src
 └ …
```
```sql
-- ./drizzle/20242409125510_seed/migration.sql

INSERT INTO [users] ([name]) VALUES('Dan');
INSERT INTO [users] ([name]) VALUES('Andrew');
INSERT INTO [users] ([name]) VALUES('Dandrew');
```
</Section>

### Ignore conflicts

In case you need `generate` command to skip commutativity checks and bypass it, you can use `--ignore-conflicts`. If there is a situation you want to use it, then
there is a big chance that `drizzle-kit` didn't check migrations right and it's a bug. Please report us your case, so we can fix it

```shell
drizzle-kit generate --ignore-conflicts
```

### Extended list of available configurations
`drizzle-kit generate` has a list of cli-only options

<rem025/>

|               |                                                      |
| :--------     | :--------------------------------------------------- |
| `custom`      | generate empty SQL for custom migration              |
| `name`        | generate migration with custom name                  |
| `ignore-conflicts` | skip commutativity conflict checks, default is `false` |
<rem025/>

<Npx>
drizzle-kit generate --name=init
drizzle-kit generate --name=seed_users --custom
drizzle-kit generate --ignore-conflicts
</Npx>

<br/>
<hr/>
<br/>
We recommend configuring `drizzle-kit` through [drizzle.config.ts](/docs/mssql/drizzle-config-file) file, 
yet you can provide all configuration options through CLI if necessary, e.g. in CI/CD pipelines, etc.

|               |            |                                                                            |
| :------------ | :-------   | :----------------------------------------------------------------------    |
| `dialect`     | `required` | Database dialect, one of <Dialects/>                                       |
| `schema`      | `required` | Path to typescript schema file(s) or folder(s) with multiple schema files  |
| `out`         |            | Migrations output folder, default is `./drizzle`                           |
| `config`      |            | Configuration file path, default is `drizzle.config.ts`                    |
| `breakpoints` |            | SQL statements breakpoints, default is `true`                              |


### Extended example
Example of how to create a custom MSSQL migration file named `0001_seed-users.sql` 
with Drizzle schema located in `./src/schema.ts` and migrations folder named `./migrations` instead of default `./drizzle`.

We will also place drizzle config file in the `configs` folder.

Let's create config file:

```plaintext {4}
📦 <project root>
 ├ 📂 migrations
 ├ 📂 configs
 │ └ 📜 drizzle.config.ts
 ├ 📂 src
 └ …
```
```ts filename='drizzle.config.ts'
import { defineConfig } from "drizzle-kit";

export default defineConfig({
  dialect: "mssql",
  schema: "./src/schema.ts",
  out: "./migrations",
});
```

Now let's run
```shell
npx drizzle-kit generate --config=./configs/drizzle.config.ts --name=seed-users --custom
```
And it will successfully generate
<Section>
```plaintext {6}
📦 <project root>
 ├ …
 ├ 📂 migrations
 │ ├ 📂 20242409125510_init
 │ └ 📂 20242409125510_seed-users
 └ …
```
```sql
-- ./drizzle/20242409125510_seed-users/migration.sql

INSERT INTO [users] ([name]) VALUES('Dan');
INSERT INTO [users] ([name]) VALUES('Andrew');
INSERT INTO [users] ([name]) VALUES('Dandrew');
```
</Section>


Source: https://orm.drizzle.team/docs/mssql/drizzle-kit-migrate

import CodeTab from "@mdx/CodeTab.astro";
import CodeTabs from "@mdx/CodeTabs.astro";
import Section from "@mdx/Section.astro";
import Tab from "@mdx/Tab.astro";
import Tabs from "@mdx/Tabs.astro";
import Callout from "@mdx/Callout.astro";
import Prerequisites from "@mdx/Prerequisites.astro";
import Npx from "@mdx/Npx.astro";

# `drizzle-kit migrate`
<Prerequisites>
- Get started with Drizzle and `drizzle-kit` - [read here](/docs/mssql/get-started)
- Drizzle schema fundamentals - [read here](/docs/mssql/sql-schema-declaration)
- Database connection basics - [read here](/docs/mssql/connect-overview)
- Drizzle migrations fundamentals - [read here](/docs/mssql/migrations)
- Drizzle Kit [overview](/docs/mssql/kit-overview) and [config file](/docs/mssql/drizzle-config-file)
- `drizzle-kit generate` command - [read here](/docs/mssql/drizzle-kit-generate)
</Prerequisites>
<br/>


`drizzle-kit migrate` lets you apply SQL migrations generated by [`drizzle-kit generate`](/docs/mssql/drizzle-kit-generate). 
It's designed to cover [code first(option 3)](/docs/mssql/migrations) approach of managing Drizzle migrations. 

<Callout collapsed="How it works under the hood?">
Drizzle Kit `migrate` command triggers a sequence of events:
1. Reads through migration folder and read all `.sql` migration files
2. Connects to the database and fetches entries from drizzle migrations log table
3. Based on previously applied migrations it will decide which new migrations to run
4. Runs SQL migrations and logs applied migrations to drizzle migrations table

<Section>
```plaintext
  ├ 📂 drizzle       
  │ ├ 📂 20242409125510_premium_mister_fear
  │ └ 📂 20242409135510_delicate_professor_xavie
  └ …
```
```plaintext
┌───────────────────────┐                  
│ $ drizzle-kit migrate │                  
└─┬─────────────────────┘                  
  │                                                         ┌──────────────────────────┐                                         
  └ 1. reads migration.sql files in migrations folder       │                          │
    2. fetch migration history from database -------------> │                          │
  ┌ 3. pick previously unapplied migrations <-------------- │         DATABASE         │
  └ 4. apply new migration to the database ---------------> │                          │
                                                            │                          │
                                                            └──────────────────────────┘
[✓] done!        
```
</Section>
</Callout>

`drizzle-kit migrate` command requires you to specify both `dialect` and database connection credentials, 
you can provide them either via [drizzle.config.ts](/docs/mssql/drizzle-config-file) config file or via CLI options

<CodeTabs items={["With config file", "As CLI options"]}>
<Section>
```ts {5,8}
// drizzle.config.ts
import { defineConfig } from "drizzle-kit";

export default defineConfig({
  dialect: "mssql",
  schema: "./src/schema.ts",
  dbCredentials: {
    url: "mssql://user:password@host:port/dbname"
  },
});
```
```shell
npx drizzle-kit migrate
```
</Section>
```shell
npx drizzle-kit migrate --dialect=mssql --url=mssql://user:password@host:port/dbname
```
</CodeTabs>

### Applied migrations log in the database
Upon running migrations Drizzle Kit will persist records about successfully applied migrations in your database. 
It will store them in migrations log table named `__drizzle_migrations` in `drizzle` schema.

You can customise both **table** and **schema** of that table via drizzle config file:
```ts filename="drizzle.config.ts" {8-9}
export default defineConfig({
  dialect: "mssql",
  schema: "./src/schema.ts",
  dbCredentials: {
    url: "mssql://user:password@host:port/dbname"
  },
  migrations: {
    table: 'my-migrations-table', // `__drizzle_migrations` by default
    schema: 'drizzle', // `drizzle` by default
  },
});
```

### Multiple configuration files in one project
You can have multiple config files in the project, it's very useful when you have multiple database stages or multiple databases on the same project:
<Npx>
  drizzle-kit migrate --config=drizzle-dev.config.ts
  drizzle-kit migrate --config=drizzle-prod.config.ts
</Npx>
```plaintext {5-6}
📦 <project root>
 ├ 📂 drizzle
 ├ 📂 src
 ├ 📜 .env
 ├ 📜 drizzle-dev.config.ts
 ├ 📜 drizzle-prod.config.ts
 ├ 📜 package.json
 └ 📜 tsconfig.json
```

### Extended example
Let's generate SQL migration and apply it to our database using `drizzle-kit generate` and `drizzle-kit migrate` commands

```plaintext
📦 <project root>
 ├ 📂 drizzle
 ├ 📂 src
 │ ├ 📜 schema.ts
 │ └ 📜 index.ts
 ├ 📜 drizzle.config.ts
 └ …
```
<CodeTabs items={["drizzle.config.ts", "src/schema.ts"]}>
```ts
import { defineConfig } from "drizzle-kit";

export default defineConfig({
  dialect: "mssql",
  schema: "./src/schema.ts",
  dbCredentials: {
    url: "mssql://user:password@host:port/dbname"
  },
  migrations: {
    table: 'journal', 
    schema: 'drizzle', 
  },
});
```
```ts 
import * as p from "drizzle-orm/mssql-core";

export const users = p.mssqlTable("users", {
  id: p.int().primaryKey().identity(),
  name: p.nvarchar({ length: 255 }),
})
```
</CodeTabs>

Now let's run
```shell
npx drizzle-kit generate --name=init
```
it will generate
<Section>
```plaintext {5}
📦 <project root>
 ├ …
 ├ 📂 migrations
 │ ├ 📂 20242409125510_init
 └ …
```
```sql
-- ./drizzle/0000_init.sql

CREATE TABLE [users] (
	[id] int IDENTITY(1, 1),
	[name] nvarchar(255),
	CONSTRAINT [users_pkey] PRIMARY KEY([id])
);
```
</Section>

Now let's run
```shell
npx drizzle-kit migrate
```

and our SQL migration is now successfully applied to the database ✅


Source: https://orm.drizzle.team/docs/mssql/drizzle-kit-pull

import CodeTab from "@mdx/CodeTab.astro";
import CodeTabs from "@mdx/CodeTabs.astro";
import Section from "@mdx/Section.astro";
import Tab from "@mdx/Tab.astro";
import Tabs from "@mdx/Tabs.astro";
import Callout from "@mdx/Callout.astro";
import Prerequisites from "@mdx/Prerequisites.astro";
import Drivers from "@mdx/Drivers.mdx"
import Dialects from "@mdx/Dialects.mdx"
import Npm from "@mdx/Npm.astro"
import Npx from "@mdx/Npx.astro"

# `drizzle-kit pull`

<Prerequisites>
- Get started with Drizzle and `drizzle-kit` - [read here](/docs/mssql/get-started)
- Drizzle schema fundamentals - [read here](/docs/mssql/sql-schema-declaration) 
- Database connection basics - [read here](/docs/mssql/connect-overview) 
- Drizzle migrations fundamentals - [read here](/docs/mssql/migrations) 
- Drizzle Kit [overview](/docs/mssql/kit-overview) and [config file](/docs/mssql/drizzle-config-file) docs
</Prerequisites>

`drizzle-kit pull` lets you literally pull(introspect) your existing database schema and generate `schema.ts` drizzle schema file, 
it is designed to cover [database first](/docs/mssql/migrations) approach of Drizzle migrations.

<Callout collapsed="How it works under the hood?">
When you run Drizzle Kit `pull` command it will:
1. Pull database schema(DDL) from your existing database
2. Generate `schema.ts` drizzle schema file and save it to `out` folder

<Section>
```
                                  ┌────────────────────────┐      ┌───────────────────────────────┐ 
                                  │                        │ <---  CREATE TABLE [users] (
┌──────────────────────────┐      │                        │        [id] int identity primary key,
│ ~ drizzle-kit pull       │      │                        │        [name] varchar(255),
└─┬────────────────────────┘      │        DATABASE        │        [email] varchar(255) unique
  │                               │                        │       );
  └ Pull datatabase schema -----> │                        │
  ┌ Generate Drizzle       <----- │                        │
  │ schema TypeScript file        └────────────────────────┘
  │
  v
```
```typescript
import * as p from "drizzle-orm/mssql-core";

export const users = p.mssqlTable("users", {
	id: p.int().identity({ seed: 1 ,increment: 1 }),
	name: p.varchar({ length: 255 }),
	email: p.varchar({ length: 255 }),
}, (table) => [
	p.primaryKey({ columns: [table.id], name: "PK__users__3213E83F9C94E8E5"}),
	p.unique("UQ__users__AB6E6164167EE806").on(table.email)
]);
```
</Section>
</Callout>

It is a great approach if you need to manage database schema outside of your TypeScript project or 
you're using database, which is managed by somebody else.

<br/>
<hr/>
<br/>

`drizzle-kit pull` requires you to specify `dialect` and either
database connection `url` or `user:password@host:port/db` params, you can provide them
either via [drizzle.config.ts](/docs/mssql/drizzle-config-file) config file or via CLI options:

<CodeTabs items={["With config file", "With CLI options"]}>
<Section>
```ts
// drizzle.config.ts
import { defineConfig } from "drizzle-kit";

export default defineConfig({
  dialect: "mssql",
  dbCredentials: {
    url: "mssql://user:password@host:port/dbname",
  },
});
```
```shell
npx drizzle-kit pull
```
</Section>

```shell
npx drizzle-kit pull --dialect=mssql --url=mssql://user:password@host:port/dbname
```
</CodeTabs>

### Multiple configuration files in one project

You can have multiple config files in the project, it's very useful when you have multiple database stages or multiple databases or different databases on the same project:

<Npx>
  drizzle-kit pull --config=drizzle-dev.config.ts
  drizzle-kit pull --config=drizzle-prod.config.ts
</Npx>
```plaintext {5-6}
📦 <project root>
 ├ 📂 drizzle
 ├ 📂 src
 ├ 📜 .env
 ├ 📜 drizzle-dev.config.ts
 ├ 📜 drizzle-prod.config.ts
 ├ 📜 package.json
 └ 📜 tsconfig.json
```

### Initial pull

You can use the `--init` flag to mark the pulled schema as an applied migration in your database, 
so that all subsequent migrations are diffed against the initial one

```shell
npx drizzle-kit pull --init
```

### Including tables and schemas
`drizzle-kit pull` will by default manage all tables in all schemas.
You can configure list of tables and schemas via `tablesFilter` and `schemaFilter` options.

|                     |                                                                                               |
| :------------------ | :-------------------------------------------------------------------------------------------- |
| `tablesFilter`      | `glob` based table names filter, e.g. `["users", "user_info"]` or `"user*"`. Default is `"*"` |
| `schemaFilter`      | `glob` based schema names filter, e.g. `["dbo", "drizzle"]` or `"drizzle*"`. Default is `"*"`                     |
<br/>

Let's configure drizzle-kit to only operate with **all tables** in **dbo** schema.

<Section>
```ts filename="drizzle.config.ts" {9-10}
import { defineConfig } from "drizzle-kit";

export default defineConfig({
  dialect: "mssql",
  schema: "./src/schema.ts",
  dbCredentials: {
    url: "mssql://user:password@host:port/dbname",
  },
  schemaFilter: ["dbo"],
  tablesFilter: ["*"],
});
```
```shell
npx drizzle-kit pull
```
</Section>

### Extended list of configurations
We recommend configuring `drizzle-kit` through [drizzle.config.ts](/docs/mssql/drizzle-config-file) file, 
yet you can provide all configuration options through CLI if necessary, e.g. in CI/CD pipelines, etc.

|                     |            |                                                                           |
| :------------------ | :--------- | :------------------------------------------------------------------------ |
| `dialect`           | `required` | Database dialect, one of <Dialects/>                                      |
| `out`               |            | Migrations output folder path, default is `./drizzle`                     |
| `url`               |            | Database connection string                                                |
| `user`              |            | Database user                                                             |
| `password`          |            | Database password                                                         |
| `host`              |            | Host                                                                      |
| `port`              |            | Port                                                                      |
| `database`          |            | Database name                                                             |
| `config`            |            | Configuration file path, default is `drizzle.config.ts`                          |
| `introspect-casing` |            | Strategy for JS keys creation in columns, tables, etc. `preserve` `camel` |
| `tablesFilter`      |            | Table name filter                                                         |
| `schemaFilter`      |            | Schema name filter. Default: `["*"]`                                 |

<Npx>
drizzle-kit pull --dialect=mssql --url=mssql://user:password@host:port/dbname
drizzle-kit pull --dialect=mssql --tablesFilter='user*' url=mssql://user:password@host:port/dbname
</Npx>

{/* TODO update gif */}
![](@/assets/gifs/introspect_mysql.gif)


Source: https://orm.drizzle.team/docs/mssql/drizzle-kit-push

import CodeTab from "@mdx/CodeTab.astro";
import CodeTabs from "@mdx/CodeTabs.astro";
import Section from "@mdx/Section.astro";
import Tab from "@mdx/Tab.astro";
import Tabs from "@mdx/Tabs.astro";
import Callout from "@mdx/Callout.astro";
import Prerequisites from "@mdx/Prerequisites.astro";
import Npx from "@mdx/Npx.astro";
import SchemaFilePaths from "@mdx/SchemaFilePaths.mdx";
import Drivers from "@mdx/Drivers.mdx"
import Dialects from "@mdx/Dialects.mdx"
import DriversExamples from "@mdx/DriversExamples.mdx"

# `drizzle-kit push`

<Prerequisites>
- Get started with Drizzle and `drizzle-kit` - [read here](/docs/mssql/get-started)
- Drizzle schema fundamentals - [read here](/docs/mssql/sql-schema-declaration) 
- Database connection basics - [read here](/docs/mssql/connect-overview) 
- Drizzle migrations fundamentals - [read here](/docs/mssql/migrations) 
- Drizzle Kit [overview](/docs/mssql/kit-overview) and [config file](/docs/mssql/drizzle-config-file) docs
</Prerequisites>


`drizzle-kit push` lets you literally push your schema and subsequent schema changes directly to the
database while omitting SQL files generation, it's designed to cover [code first](/docs/mssql/migrations)
approach of Drizzle migrations.

<Callout collapsed="How it works under the hood?">
When you run Drizzle Kit `push` command it will:
1. Read through your Drizzle schema file(s) and compose a json snapshot of your schema
2. Pull(introspect) database schema 
3. Based on differences between those two it will generate SQL migrations
4. Apply SQL migrations to the database

<Section>
```typescript filename="src/schema.ts"
import * as p from "drizzle-orm/mssql-core";

export const users = p.mssqlTable("users", {
  id: p.int().primaryKey().identity(),
  name: p.nvarchar({ length: 255 }),
});
```
```
┌─────────────────────┐                  
│ ~ drizzle-kit push  │                  
└─┬───────────────────┘                  
  │                                           ┌──────────────────────────┐
  └ Pull current datatabase schema ---------> │                          │
                                              │                          │
  ┌ Generate alternations based on diff <---- │         DATABASE         │
  │                                           │                          │
  └ Apply migrations to the database -------> │                          │
                                       │      └──────────────────────────┘
                                       │
  ┌────────────────────────────────────┴─────┐
   CREATE TABLE [users] (
     [id] int IDENTITY(1, 1),
     [name] nvarchar(255),
     CONSTRAINT [users_pkey] PRIMARY KEY([id])
   );
```
</Section>
</Callout>

It's the best approach for rapid prototyping and we've seen dozens of teams
and solo developers successfully using it as a primary migrations flow in their production applications.
It pairs exceptionally well with blue/green deployment strategy, managed database deployments, and CI/CD workflows.

<br/>
<hr/>
<br/>


`drizzle-kit push` requires you to specify `dialect`, path to the `schema` file(s) and either
database connection `url` or `user:password@host:port/db` params, you can provide them
either via [drizzle.config.ts](/docs/mssql/drizzle-config-file) config file or via CLI options:

<CodeTabs items={["With config file", "With CLI options"]}>
<Section>
```ts
// drizzle.config.ts
import { defineConfig } from "drizzle-kit";

export default defineConfig({
  dialect: "mssql",
  schema: "./src/schema.ts",
  dbCredentials: {
    url: "mssql://user:password@host:port/dbname",
  },
});
```
```shell
npx drizzle-kit push
```
</Section>

```shell
npx drizzle-kit push --dialect=mssql --schema=./src/schema.ts --url=mssql://user:password@host:port/dbname
```

</CodeTabs>

### Schema files path

You can have a single `schema.ts` file or as many schema files as you want spread out across the project.
Drizzle Kit requires you to specify path(s) to them as a [glob](https://www.digitalocean.com/community/tools/glob?comments=true&glob=/**/*.js&matches=false&tests=//%20This%20will%20match%20as%20it%20ends%20with%20'.js'&tests=/hello/world.js&tests=//%20This%20won't%20match!&tests=/test/some/globs) via `schema` configuration option.

<SchemaFilePaths />

### Multiple configuration files in one project

You can have multiple config files in the project, it's very useful when you have multiple database stages or multiple databases or different databases on the same project:

<Npx>
  drizzle-kit push --config=drizzle-dev.config.ts
  drizzle-kit push --config=drizzle-prod.config.ts
</Npx>
```plaintext {5-6}
📦 <project root>
 ├ 📂 drizzle
 ├ 📂 src
 ├ 📜 .env
 ├ 📜 drizzle-dev.config.ts
 ├ 📜 drizzle-prod.config.ts
 ├ 📜 package.json
 └ 📜 tsconfig.json
```

### Including tables and schemas
`drizzle-kit push` will manage all tables and schemas by default.
You can configure list of tables, schemas via `tablesFilter`, `schemaFilter` options.

|                     |                                                                                               |
| :------------------ | :-------------------------------------------------------------------------------------------- |
| `tablesFilter`      | `glob` based table names filter, e.g. `["users", "user_info"]` or `"user*"`. Default is `"*"` |
| `schemaFilter`      | Schema names filter, e.g. `["dbo", "drizzle"]`                                             |
<br/>

Let's configure drizzle-kit to only operate with **all tables** in **dbo** schema.

<Section>
```ts filename="drizzle.config.ts" {9-10}
import { defineConfig } from "drizzle-kit";

export default defineConfig({
  dialect: "mssql",
  schema: "./src/schema.ts",
  dbCredentials: {
    url: "mssql://user:password@host:port/dbname",
  },
  schemaFilter: ["dbo"],
  tablesFilter: ["*"],
});
```
```shell
npx drizzle-kit push
```
</Section>

### Extended list of configurations

`drizzle-kit push` has a list of cli-only options

<rem025/>

|           |                                                                 |
| :-------- | :---------------------------------------------------------------|
| `verbose` | print all SQL statements prior to execution                     |
| `explain` | print the planned SQL changes, without applying them (dry run)  |
| `force`   | auto-accept all data-loss statements                            |
<br/>
<Npx>
drizzle-kit push --explain --verbose --force
</Npx>

<br/>
<hr/>
<br/>
We recommend configuring `drizzle-kit` through [drizzle.config.ts](/docs/mssql/drizzle-config-file) file, 
yet you can provide all configuration options through CLI if necessary, e.g. in CI/CD pipelines, etc.

|                     |            |                                                                           |
| :------------------ | :--------- | :------------------------------------------------------------------------ |
| `dialect`           | `required` | Database dialect, one of <Dialects/>                                      |
| `schema`            | `required` | Path to typescript schema file(s) or folder(s) with multiple schema files |
| `tablesFilter`      |            | Table name filter                                                         |
| `schemaFilter`      |            | Schema name filter. Default: `["*"]`                                 |
| `url`               |            | Database connection string                                                |
| `user`              |            | Database user                                                             |
| `password`          |            | Database password                                                         |
| `host`              |            | Host                                                                      |
| `port`              |            | Port                                                                      |
| `database`          |            | Database name                                                             |
| `config`            |            | Configuration file path, default=`drizzle.config.ts`                             |

<Npx>
drizzle-kit push dialect=mssql schema=src/schema.ts url=mssql://user:password@host:port/dbname
drizzle-kit push dialect=mssql schema=src/schema.ts --tablesFilter='user*' url=mssql://user:password@host:port/dbname
</Npx>


### Extended example
Let's declare drizzle schema in the project and push it to the database via `drizzle-kit push` command

```plaintext
📦 <project root>
 ├ 📂 src
 │ ├ 📜 schema.ts
 │ └ 📜 index.ts
 ├ 📜 drizzle.config.ts
 └ …
```
<CodeTabs items={["drizzle.config.ts", "src/schema.ts"]}>
```ts
import { defineConfig } from "drizzle-kit";

export default defineConfig({
  dialect: "mssql",
  schema: "./src/schema.ts",
  dbCredentials: {
    url: "mssql://user:password@host:port/dbname"
  },
});
```
```ts 
import * as p from "drizzle-orm/mssql-core";

export const users = p.mssqlTable("users", {
  id: p.int().primaryKey().identity(),
  name: p.nvarchar({ length: 255 }),
})
```
</CodeTabs>

Now let's run
```shell
npx drizzle-kit push
```

it will pull existing(empty) schema from the database and generate SQL migration and apply it under the hood
```sql
CREATE TABLE [users] (
	[id] int IDENTITY(1, 1),
	[name] nvarchar(255),
	CONSTRAINT [users_pkey] PRIMARY KEY([id])
);
```

DONE ✅


Source: https://orm.drizzle.team/docs/mssql/drizzle-kit-studio

import CodeTab from "@mdx/CodeTab.astro";
import CodeTabs from "@mdx/CodeTabs.astro";
import Section from "@mdx/Section.astro";
import Tab from "@mdx/Tab.astro";
import Tabs from "@mdx/Tabs.astro";
import Callout from "@mdx/Callout.astro";
import Prerequisites from "@mdx/Prerequisites.astro";
import Npm from "@mdx/Npm.astro";
import Npx from "@mdx/Npx.astro";


# `drizzle-kit studio`
<Prerequisites>
- Drizzle Kit [overview](/docs/mssql/kit-overview) and [config file](/docs/mssql/drizzle-config-file)
- Drizzle Studio, our database browser - [read here](/drizzle-studio/overview)
</Prerequisites>

`drizzle-kit studio` command spins up a server for [Drizzle Studio](/drizzle-studio/overview) hosted on [local.drizzle.studio](https://local.drizzle.studio). 
It requires you to specify database connection credentials via [drizzle.config.ts](/docs/mssql/drizzle-config-file) config file.

By default it will start a Drizzle Studio server on `127.0.0.1:4983`
<Section>
```ts {6}
// drizzle.config.ts
import { defineConfig } from "drizzle-kit";

export default defineConfig({
  dialect: "mssql",
  dbCredentials: {
    url: "mssql://user:password@host:port/dbname"
  },
});
```
```shell
npx drizzle-kit studio
```
</Section>

### Configuring `host` and `port`
By default Drizzle Studio server starts on `127.0.0.1:4983`, 
you can config `host` and `port` via CLI options

<Npx>
drizzle-kit studio --port=3000
drizzle-kit studio --host=0.0.0.0
drizzle-kit studio --host=0.0.0.0 --port=3000
</Npx>


### Logging
You can enable logging of every SQL statement by providing `verbose` flag

<Npx>
drizzle-kit studio --verbose
</Npx>

### Safari and Brave support
Safari and Brave block access to localhost by default. 
You need to install [mkcert](https://github.com/FiloSottile/mkcert) and generate self-signed certificate:

1. Follow the mkcert [installation steps](https://github.com/FiloSottile/mkcert#installation)
2. Run `mkcert -install`
3. Restart your `drizzle-kit studio`

### Other flavours of Drizzle Studio
Apart from `drizzle-kit studio` for local development, Drizzle Studio also comes as a self-hosted
Drizzle Gateway, a Chrome extension for serverless database vendors and an embeddable component
for your own product — check out the [Drizzle Studio overview](/drizzle-studio/overview).

### Limitations
Our hosted version Drizzle Studio is meant to be used for local development and not meant to be used on remote (VPS, etc).

If you want to deploy Drizzle Studio to your VPS — that's what
[Drizzle Gateway](/drizzle-studio/overview#drizzle-gateway) is for.

### Is it open source?
No. Drizzle ORM and Drizzle Kit are fully open sourced, while Studio is not. 

Drizzle Studio for local development is free to use forever to enrich Drizzle ecosystem, 
open sourcing one would've break our ability to provide B2B offerings and monetise it, unfortunately.


Source: https://orm.drizzle.team/docs/mssql/drizzle-kit-up

import CodeTab from "@mdx/CodeTab.astro";
import CodeTabs from "@mdx/CodeTabs.astro";
import Section from "@mdx/Section.astro";
import Tab from "@mdx/Tab.astro";
import Tabs from "@mdx/Tabs.astro";
import Callout from "@mdx/Callout.astro";
import Prerequisites from "@mdx/Prerequisites.astro";
import Npx from "@mdx/Npx.astro";
import Dialects from "@mdx/Dialects.mdx"

# `drizzle-kit up`

<Prerequisites>
- Get started with Drizzle and `drizzle-kit` - [read here](/docs/mssql/get-started)
- Drizzle schema fundamentals - [read here](/docs/mssql/sql-schema-declaration)
- Database connection basics - [read here](/docs/mssql/connect-overview)
- Drizzle migrations fundamentals - [read here](/docs/mssql/migrations)
- Drizzle Kit [overview](/docs/mssql/kit-overview) and [config file](/docs/mssql/drizzle-config-file)
- `drizzle-kit generate` command - [read here](/docs/mssql/drizzle-kit-generate)
</Prerequisites>

`drizzle-kit up` command lets you upgrade drizzle schema snapshots to a newer version. 
It's required whenever we introduce breaking changes to the json snapshots of the schema and upgrade the internal version.

<br/>
<hr/>
<br/>

`drizzle-kit up` command requires you to specify `dialect` param,
you can provide it either via [drizzle.config.ts](/docs/mssql/drizzle-config-file) config file or via CLI options

<CodeTabs items={["With config file", "As CLI options"]}>
<Section>
```ts {5,8}
// drizzle.config.ts
import { defineConfig } from "drizzle-kit";

export default defineConfig({
  dialect: "mssql",
});
```
```shell
npx drizzle-kit up
```
</Section>
```shell
npx drizzle-kit up --dialect=mssql
```
</CodeTabs>

### Multiple configuration files in one project
You can have multiple config files in the project, it's very useful when you have multiple database stages or multiple databases on the same project:
<Npx>
  drizzle-kit migrate --config=drizzle-dev.config.ts
  drizzle-kit migrate --config=drizzle-prod.config.ts
</Npx>
```plaintext {5-6}
📦 <project root>
 ├ 📂 drizzle
 ├ 📂 src
 ├ 📜 .env
 ├ 📜 drizzle-dev.config.ts
 ├ 📜 drizzle-prod.config.ts
 ├ 📜 package.json
 └ 📜 tsconfig.json
```

### Extended list of configurations
We recommend configuring `drizzle-kit` through [drizzle.config.ts](/docs/mssql/drizzle-config-file) file, 
yet you can provide all configuration options through CLI if necessary, e.g. in CI/CD pipelines, etc.
<rem025/>
|           |            |                                                                         |
| :-------- | :--------- | :---------------------------------------------------------------------- |
| `dialect` | `required` | Database dialect you are using. Can be one of <Dialects/> |
| `out`     |            | Migrations folder, default=`./drizzle`                                  |
| `config`  |            | Configuration file path, default=`drizzle.config.ts`                           |
<br/>
<Npx>
drizzle-kit up --dialect=mssql
drizzle-kit up --dialect=mssql --out=./migrations-folder
</Npx>

{/* TODO: update up gif */}
![](@/assets/gifs/up_mysql.gif)


Source: https://orm.drizzle.team/docs/mssql/dynamic-query-building

import Callout from '@mdx/Callout.astro';

# Dynamic query building

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
```

In the previous ORM versions, when such restrictions weren't implemented, this example in particular was a source of confusion for many users, as they expected the query builder to "merge" multiple `.where()` calls into a single condition.

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 `OFFSET` and `FETCH` clauses to a query based on the provided page number and an optional page size:

```ts
function withPagination<T extends MsSqlSelect>(
	qb: T,
	page: number = 1,
	pageSize: number = 10,
) {
	return qb.offset((page - 1) * pageSize).fetch(pageSize);
}

const query = db.select().from(users).where(eq(users.id, 1)).orderBy(users.id);
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 MsSqlSelect>(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);
```

This is possible, because `MsSqlSelect` and other similar types are specifically designed to be used in dynamic query building. They can only be used in dynamic mode.

Here is the list of all types that can be used as generic parameters in dynamic query building:

| Query  | Type                              |
|:--------|:-----------------------------------|
| Select | `MsSqlSelect` / `MsSqlSelectQueryBuilder` |
| Insert | `MsSqlInsert`                        |
| Update | `MsSqlUpdate`                        |
| Delete | `MsSqlDelete`                        |

<Callout type='info'>
	The `...QueryBuilder` types are for usage with [standalone query builder
	instances](/docs/mssql/goodies#standalone-query-builder). DB query builders are
	subclasses of them, so you can use them as well.

```ts
import { QueryBuilder } from 'drizzle-orm/mssql-core';

function withFriends<T extends MsSqlSelectQueryBuilder>(qb: T) {
	return qb.leftJoin(friends, eq(friends.userId, users.id));
}

const qb = new QueryBuilder();
let query = qb.select().from(users).where(eq(users.id, 1)).$dynamic();
query = withFriends(query);
```

</Callout>


Source: https://orm.drizzle.team/docs/mssql/effect-schema

import Npm from '@mdx/Npm.astro';
import Callout from '@mdx/Callout.astro';

# effect-schema

Allows you to generate [effect](https://effect.website/) schemas from Drizzle ORM schemas.

**Features**

- Create a select schema for tables and views.
- Create insert and update schemas for tables.
- Supported dialect: MSSQL.

#### Usage

```ts
import { int, mssqlTable, text, datetime2 } from 'drizzle-orm/mssql-core';
import { createInsertSchema, createSelectSchema, createUpdateSchema } from 'drizzle-orm/effect-schema';
import { Effect, Schema } from "effect";

const users = mssqlTable('users', {
	id: int().primaryKey().identity(),
	name: text().notNull(),
	email: text().notNull(),
	role: text({ enum: ['admin', 'user'] }).notNull(),
	createdAt: datetime2('created_at').notNull(),
});

// Schema for inserting a user - can be used to validate API requests
const UserInsert = createInsertSchema(users);

// Schema for updating a user - can be used to validate API requests
const UserUpdate = createUpdateSchema(users);

// Schema for selecting a user - can be used to validate API responses
const UserSelect = createSelectSchema(users);

// Overriding the fields
const UserInsert = createInsertSchema(users, {
	role: Schema.String,
});

// Refining the fields - useful if you want to change the fields before they become nullable/optional in the final schema
const UserInsert = createInsertSchema(users, {
	id: (schema) => schema.check(Schema.isGreaterThanOrEqualTo(0)),
	role: Schema.String,
});

// Usage
const program = Effect.gen(function*() {
	const parsedUser = yield* Schema.decodeUnknownEffect(UserInsert)({
		name: 'John Doe',
		email: 'johndoe@test.com',
		role: 'admin',
	});
});
```

Source: https://orm.drizzle.team/docs/mssql/extensions


import Callout from '@mdx/Callout.astro';

<Callout>
Currently, there are no MSSQL extensions natively supported by Drizzle. Once those are added, we will have them here!
</Callout>

Source: https://orm.drizzle.team/docs/mssql/generated-columns

import CodeTabs from '@mdx/CodeTabs.astro';
import CodeTab from '@mdx/CodeTab.astro';
import Callout from '@mdx/Callout.astro';

# Generated Columns

MSSQL supports computed columns. A computed column is calculated from an expression that can reference other columns in the same table.

1. Virtual computed columns are calculated when queried and do not occupy storage space.

2. Persisted computed columns store the computed value on disk and can be indexed when the expression is deterministic.

For more info, see the Microsoft docs for [computed columns](https://learn.microsoft.com/en-us/sql/relational-databases/tables/specify-computed-columns-in-a-table).

#### Drizzle Side

In Drizzle you can specify `.generatedAlwaysAs()` on a column and pass a SQL expression.

#### Virtual Computed Column

<CodeTab>
```ts
import { SQL, sql } from "drizzle-orm";
import { mssqlTable, varchar } from "drizzle-orm/mssql-core";

export const users = mssqlTable("users", {
  firstName: varchar("first_name", { length: 256 }),
  lastName: varchar("last_name", { length: 256 }),
  fullName: varchar("full_name", { length: 512 }).generatedAlwaysAs(
    (): SQL => sql`concat(${users.firstName}, ' ', ${users.lastName})`,
  ),
});
```

```sql
CREATE TABLE [users] (
  [first_name] varchar(256),
  [last_name] varchar(256),
  [full_name] AS (concat([users].[first_name], ' ', [users].[last_name]))
);
```
</CodeTab>

#### Persisted Computed Column

Use `{ mode: "persisted" }` when you want SQL Server to persist the computed value.

<CodeTabs items={["schema.ts", "SQL"]}>
<CodeTab>
```typescript copy
import { SQL, sql } from "drizzle-orm";
import { int, mssqlTable, varchar } from "drizzle-orm/mssql-core";

export const orders = mssqlTable("orders", {
  quantity: int("quantity"),
  unitPrice: int("unit_price"),
  total: int("total").generatedAlwaysAs(
    (): SQL => sql`${orders.quantity} * ${orders.unitPrice}`,
    { mode: "persisted" },
  ),
});
```
</CodeTab>
<CodeTab>
```sql
CREATE TABLE [orders] (
  [quantity] int,
  [unit_price] int,
  [total] AS ([orders].[quantity] * [orders].[unit_price]) PERSISTED
);
```
</CodeTab>
</CodeTabs>

#### Limitations

Drizzle Kit will also have limitations for `push` command:
1. You can't change the generated constraint expression using `push`. Drizzle-kit will ignore this change. To make it work, you would need to `drop the column`, `push`, and then `add a column with a new expression`. This was done due to the complex mapping from the database side, where the schema expression will be modified on the database side and, on introspection, we will get a different string. We can't be sure if you changed this expression or if it was changed and formatted by the database. As long as these are generated columns and `push` is mostly used for prototyping on a local database, it should be fast to `drop` and `create` generated columns. Since these columns are `generated`, all the data will be restored
2. `generate` should have no limitations


Source: https://orm.drizzle.team/docs/mssql/get-started-mssql

import Tab from '@mdx/Tab.astro';
import Tabs from '@mdx/Tabs.astro';
import Npm from "@mdx/Npm.astro";
import Callout from '@mdx/Callout.astro';
import Steps from '@mdx/Steps.astro';
import AnchorCards from '@mdx/AnchorCards.astro';
import Prerequisites from "@mdx/Prerequisites.astro";
import CodeTabs from "@mdx/CodeTabs.astro";
import WhatsNextMSSQL from "@mdx/WhatsNextMSSQL.astro";

# Drizzle \<\> MSSQL

<br/>

<Prerequisites>
- Database [connection basics](/docs/mssql/connect-overview) with Drizzle
- node-mssql [basics](https://github.com/tediousjs/node-mssql)
</Prerequisites>

Drizzle has native support for MSSQL connections with the `mssql` driver.

#### Step 1 - Install packages
<Npm>
 drizzle-orm@rc mssql
 -D drizzle-kit@rc
</Npm>

#### Step 2 - Initialize the driver and make a query
<CodeTabs items={["mssql", "mssql with config"]}>
```typescript copy
// Make sure to install the 'mssql' package 
import { drizzle } from 'drizzle-orm/node-mssql';

const db = drizzle(process.env.DATABASE_URL);
 
const result = await db.execute('select 1');
```
```typescript copy
// Make sure to install the 'mssql' package 
import { drizzle } from 'drizzle-orm/node-mssql';

const db = drizzle({
  connection: process.env.DATABASE_URL,
});
 
const result = await db.execute('select 1');
```
</CodeTabs>

<Callout type='warning'>
As long as the `node-mssql` driver requires `await` on `Pool` initialization, we need to `await` it before each request - unless you are providing your own Pool instance to Drizzle. In that case, when you want to access `db.$client`, you first need to `await` it, and then use it

```ts
const awaitedClient = await db.$client.$instance();
const response = awaitedClient.query...;
```
</Callout>

If you need to provide your existing driver:

```typescript copy
// Make sure to install the 'mssql' package 
import { drizzle } from "drizzle-orm/node-mssql";
import { connect } from 'mssql';

const pool = await connect(process.env.DATABASE_URL!);
const db = drizzle({ client: pool });
 
const result = await db.execute('select 1');
```

#### What's next?

<WhatsNextMSSQL/>


Source: https://orm.drizzle.team/docs/mssql/goodies

import Callout from '@mdx/Callout.astro';
import CodeTabs from '@mdx/CodeTabs.astro';

## Type API
Use Drizzle's type helpers to infer `select` and `insert` models from a MSSQL table schema.

```ts
import { int, text, mssqlTable } from 'drizzle-orm/mssql-core';
import { type InferSelectModel, type InferInsertModel } from 'drizzle-orm';

const users = mssqlTable('users', {
  id: int().identity().primaryKey(),
  name: text().notNull(),
});

type SelectUser = typeof users.$inferSelect;
type InsertUser = typeof users.$inferInsert;
// or
type SelectUser = InferSelectModel<typeof users>;
type InsertUser = InferInsertModel<typeof users>;
```

## Logging
Enable default query logging by passing `{ logger: true }` to `drizzle`.

```ts
import { drizzle } from "drizzle-orm/node-mssql";

const db = drizzle(process.env.DB_URL, { logger: true });
```

You can change the logs destination by creating a `DefaultLogger` instance and providing a custom `writer` to it:
```typescript copy
import { DefaultLogger, type LogWriter } from "drizzle-orm/logger";
import { drizzle } from "drizzle-orm/node-mssql";

class MyLogWriter implements LogWriter {
  write(message: string) {
    // Write to file, stdout, etc.
  }
}

const logger = new DefaultLogger({ writer: new MyLogWriter() });
const db = drizzle(process.env.DB_URL, { logger });
```

You can also provide a custom logger.

```ts
import type { Logger } from 'drizzle-orm/logger';
import { drizzle } from "drizzle-orm/node-mssql";

class MyLogger implements Logger {
  logQuery(query: string, params: unknown[]): void {
    console.log({ query, params });
  }
}

const db = drizzle(process.env.DB_URL, { logger: new MyLogger() });
```

## Multi-project schema
Use `mssqlTableCreator` to customize table names when several projects share one database.

```ts
import { int, text, mssqlTableCreator } from 'drizzle-orm/mssql-core';

const mssqlTable = mssqlTableCreator((name) => `project1_${name}`);

export const users = mssqlTable('users', {
  id: int().identity().primaryKey(),
  name: text().notNull(),
});

```

```ts
import { defineConfig } from 'drizzle-kit';

export default defineConfig({
  schema: './src/schema/*',
  out: './drizzle',
  dialect: 'mssql',
  dbCredentials: {
    url: process.env.DATABASE_URL!,
  },
  tablesFilter: ['project1_*'],
});
```
```sql
CREATE TABLE [project1_users] (
	[id] int IDENTITY(1, 1),
	[name] text NOT NULL,
	CONSTRAINT [project1_users_pkey] PRIMARY KEY([id])
);
```

## Printing SQL Query
Print generated SQL from a query with `.toSQL()`.

```ts
const query = db
  .select({ id: users.id, name: users.name })
  .from(users)
  .groupBy(users.id)
  .toSQL();
```

## Raw SQL Queries
Use `db.execute` for raw parametrized SQL.

```ts
import { sql } from 'drizzle-orm';

const statement = sql`select * from ${users} where ${users.id} = ${userId}`;
const result = await db.execute(statement);
```

## Standalone Query Builder
Use the MSSQL query builder without creating a database instance.

```ts
import { QueryBuilder } from 'drizzle-orm/mssql-core';

const qb = new QueryBuilder();
const query = qb.select().from(users).where(eq(users.name, 'Dan'));
const { sql, params } = query.toSQL();
```

## Get Typed Columns
Use `getColumns` to get a typed column map, which is useful when excluding fields from a selection.

<CodeTabs items={["index.ts", "schema.ts"]}>
```ts
import { getColumns } from 'drizzle-orm';
import { users } from './schema';

const { password, role, ...rest } = getColumns(users);

await db.select({ ...rest }).from(users);
```
```ts
import { int, text, mssqlTable } from "drizzle-orm/mssql-core";

export const user = mssqlTable("user", {
  id: int().identity().primaryKey(),
  name: text(),
  email: text(),
  password: text(),
  role: text().$type<"admin" | "customer">(),
});
```
</CodeTabs>

## Get Table Information
Use `getTableConfig` to inspect PostgreSQL table metadata.

```ts
import { getTableConfig, mssqlTable } from 'drizzle-orm/mssql-core';

export const table = mssqlTable(...);

const { columns, indexes, foreignKeys, checks, primaryKeys, name, schema } =
  getTableConfig(table);
```

## Compare Object Types
Use `is()` instead of `instanceof` to check Drizzle object types.

```ts
import { Column, is } from 'drizzle-orm';

if (is(value, Column)) {
  // value is narrowed to Column
}
```

## Mock Driver
Use `drizzle.mock()` when you need a typed database object without a real PostgreSQL connection.

```ts
import { drizzle } from 'drizzle-orm/node-mssql';
import * as schema from './schema';

const db = drizzle.mock({ schema });
```


Source: https://orm.drizzle.team/docs/mssql/indexes-constraints

import Callout from '@mdx/Callout.astro';
import Section from '@mdx/Section.astro';

# Indexes & Constraints

## Constraints

SQL constraints are the rules enforced on table columns. They are used to prevent invalid data from being entered into the database.

This ensures the accuracy and reliability of your data in the database.

### Default

The `DEFAULT` clause specifies a default value to use for the column if no value provided by the user when doing an `INSERT`.
If there is no explicit `DEFAULT` clause attached to a column definition,
then the default value of the column is `NULL`.

An explicit `DEFAULT` clause may specify that the default value is `NULL`,
a string constant, a blob constant, a signed-number, or any constant expression enclosed in parentheses.

<Section>
    ```typescript
    import { sql } from "drizzle-orm";
    import { int, time, mssqlTable } from "drizzle-orm/mssql-core";
    
    export const table = mssqlTable("table", {
      int: int().default(42),
      time: time().default(sql`cast('14:06:10' AS TIME)`),
    });
    ```
    ```sql
    CREATE TABLE [table] (
      [int] int CONSTRAINT [table_int_default] DEFAULT ((42)),
      [time] time CONSTRAINT [table_time_default] DEFAULT (cast('14:06:10' AS TIME))
    );
    ```
    </Section>

### Not null

By default, a column can hold **NULL** values. The `NOT NULL` constraint enforces a column to **NOT** accept **NULL** values.  

This enforces a field to always contain a value, which means that you cannot insert a new record,
or update a record without adding a value to this field.

<Section>
      ```typescript
      import { int, mssqlTable } from "drizzle-orm/mssql-core";

      export const table = mssqlTable('table', {
        int: int().notNull(),
      });
      ```

      ```sql
      CREATE TABLE [table] (
        [int] int NOT NULL
      );
      ```
    </Section>

### Unique

The `UNIQUE` constraint ensures that all values in a column are different.  

Both the `UNIQUE` and `PRIMARY KEY` constraints provide a guarantee for uniqueness for a column or set of columns.

A `PRIMARY KEY` constraint automatically has a `UNIQUE` constraint.  

<Callout type="info" emoji="ℹ️">
  You can have many `UNIQUE` constraints per table, but only one `PRIMARY KEY` constraint per table.
</Callout>

<Section>
      ```typescript
      import { int, varchar, unique, mssqlTable } from "drizzle-orm/mssql-core";

      export const user = mssqlTable('user', {
        id: int().unique(),
      });

      export const table = mssqlTable('table', {
        id: int().unique('custom_name_1'),
      });

      export const composite = mssqlTable('composite_example', {
        id: int(),
        name: varchar({ length: 256 }),
      }, (t) => [
        unique().on(t.id, t.name),
        unique('custom_name_2').on(t.id, t.name)
      ]);
      ```

      ```sql
      CREATE TABLE [user] (
      	[id] int,
      	CONSTRAINT [user_id_key] UNIQUE([id])
      );

      CREATE TABLE [table] (
      	[id] int,
      	CONSTRAINT [custom_name_1] UNIQUE([id])
      );

      CREATE TABLE [composite_example] (
        [id] int,
        [name] varchar(256),
        CONSTRAINT [composite_example_id_name_key] UNIQUE([id],[name]),
        CONSTRAINT [custom_name_2] UNIQUE([id],[name])
      );
      ```
    </Section>

### Check

The `CHECK` constraint is used to limit the value range that can be placed in a column.

If you define a `CHECK` constraint on a column it will allow only certain values for this column.  

If you define a `CHECK` constraint on a table it can limit the values in certain columns based on values in other columns in the row.

<Section>
      ```typescript copy
      import { sql } from "drizzle-orm";
      import { check, int, mssqlTable, text } from "drizzle-orm/mssql-core";

      export const users = mssqlTable(
        "users",
        {
          id: int().primaryKey(),
          username: text().notNull(),
          age: int(),
        },
        (table) => [
          check("age_check1", sql`${table.age} > 21`)
        ]
      );
      ```
      ```sql
      CREATE TABLE [users] (
          [id] int,
          [username] text NOT NULL,
          [age] int,
          CONSTRAINT [users_pkey] PRIMARY KEY([id]),
          CONSTRAINT [age_check1] CHECK ([users].[age] > 21)
      );
      ```
    </Section>

### Primary Key

The `PRIMARY KEY` constraint uniquely identifies each record in a table.  
Primary keys must contain `UNIQUE` values, and cannot contain `NULL` values.  

A table can have only **ONE** primary key; and in the table, this primary key can consist of single or multiple columns (fields).

<Section>
      ```typescript
      import { int, mssqlTable } from "drizzle-orm/mssql-core";

      export const user = mssqlTable("user", {
        id: int().identity().primaryKey(),
      })

      export const table = mssqlTable("table", {
        id: int().primaryKey(),
      })
      ```

      ```sql
      CREATE TABLE [user] (
        [id] int IDENTITY(1, 1),
        CONSTRAINT [user_pkey] PRIMARY KEY([id])
      );

      CREATE TABLE [table] (
        [id] int,
        CONSTRAINT [table_pkey] PRIMARY KEY([id])
      );
      ```
    </Section>

### Composite Primary Key

Just like `PRIMARY KEY`, composite primary key uniquely identifies each record in a table using multiple fields.

Drizzle ORM provides a standalone `primaryKey` operator for that:

<Section>
      ```typescript {18, 19}
      import { int, text, primaryKey, mssqlTable } from "drizzle-orm/mssql-core";

      export const user = mssqlTable("user", {
        id: int().identity().primaryKey(),
        name: text(),
      });

      export const book = mssqlTable("book", {
        id: int().identity().primaryKey(),
        name: text(),
      });

      export const booksToAuthors = mssqlTable("books_to_authors", {
        authorId: int("author_id"),
        bookId: int("book_id"),
      }, (table) => [
        primaryKey({ columns: [table.bookId, table.authorId] }),
        // Or PK with custom name
        primaryKey({ name: 'custom_name', columns: [table.bookId, table.authorId] })
      ]);
      ```

      ```sql {6}
      ...

      CREATE TABLE [books_to_authors] (
      	[author_id] int,
      	[book_id] int,
      	CONSTRAINT [books_to_authors_pkey] PRIMARY KEY([book_id],[author_id])
      );
      ```
    </Section>

### Foreign key

The `FOREIGN KEY` constraint is used to prevent actions that would destroy links between tables.
A `FOREIGN KEY` is a field (or collection of fields) in one table, that refers to the `PRIMARY KEY` in another table.
The table with the foreign key is called the child table, and the table with the primary key is called the referenced or parent table.

Drizzle ORM provides several ways to declare foreign keys.
You can declare them in a column declaration statement:

```typescript {11}
import { int, text, mssqlTable } from "drizzle-orm/mssql-core";

export const user = mssqlTable("user", {
  id: int().primaryKey().identity(),
  name: text(),
});

export const book = mssqlTable("book", {
  id: int().primaryKey().identity(),
  name: text(),
  authorId: int("author_id").references(() => user.id)
});
```

If you want to do a self reference, due to a TypeScript limitations you will have to either explicitly
set return type for reference callback or use a standalone `foreignKey` operator.

```typescript {6,16-19}
import { int, text, foreignKey, type AnyMsSqlColumn, mssqlTable } from "drizzle-orm/mssql-core";

export const user = mssqlTable("user", {
  id: int().primaryKey().identity(),
  name: text(),
  parentId: int("parent_id").references((): AnyMsSqlColumn => user.id),
});

// or
export const user = mssqlTable("user", {
  id: int().primaryKey().identity(),
  name: text(),
  parentId: int("parent_id")
}, (table) => [
  foreignKey({
    columns: [table.parentId],
    foreignColumns: [table.id],
    name: "custom_fk"
  })
]);
```

To declare multi-column foreign keys you can use a dedicated `foreignKey` operator:

```typescript copy {4-5,14-15,18-21}
import { int, varchar, primaryKey, foreignKey, mssqlTable } from "drizzle-orm/mssql-core";

export const user = mssqlTable("user", {
  firstName: varchar('firstName', { length: 100 }),
  lastName: varchar('lastName', { length: 100 }),
}, (table) => [
  primaryKey({ columns: [table.firstName, table.lastName]})
]);

export const profile = mssqlTable("profile", {
  id: int("id").identity().primaryKey(),
  userFirstName: varchar("user_first_name", { length: 100 }),
  userLastName: varchar("user_last_name", { length: 100 }),
}, (table) => [
  foreignKey({
    columns: [table.userFirstName, table.userLastName],
    foreignColumns: [user.firstName, user.lastName],
    name: "custom_name"
  })
]);
```

## Indexes

Drizzle ORM provides API for both `index` and `unique index` declaration:

<Section>
    ```typescript copy {9-10}
    import { int, varchar, index, uniqueIndex, mssqlTable } from "drizzle-orm/mssql-core";

    export const user = mssqlTable("user", {
      id: int().primaryKey().identity(),
      name: varchar({ length: 256 }),
      email: varchar({ length: 256 }),
    }, (table) => [
      index("name_idx").on(table.name),
      uniqueIndex("email_idx").on(table.email),
    ]);
    ```
    ```sql {5-6}
    CREATE TABLE `user` (
      ...
    );

    CREATE INDEX [name_idx] ON [user] ([name]);
    CREATE UNIQUE INDEX [email_idx] ON [user] ([email]);
    ```
    </Section>

     Drizzle ORM provides set of all params for index creation:

    ```typescript
    // Index declaration reference
    index('name_idx')
      .on(table.name)
      .where(sql``)
    ```


Source: https://orm.drizzle.team/docs/mssql/insert

import Section from '@mdx/Section.astro';
import Callout from '@mdx/Callout.astro';
import Tab from '@mdx/Tab.astro';
import Tabs from '@mdx/Tabs.astro';

# SQL Insert

<Callout type='info'>
All the values provided to `.values()`are parameterized automatically.
For example, this query:
```ts
await db.insert(users).values({ name: 'Andrew' });
```
will be translated to:
```sql
insert into [users] ([name]) values (@par0); -- params: ['Andrew']
```
</Callout>

<br/>

Drizzle ORM provides you the most SQL-like way to insert rows into the database tables.

Inserting data with Drizzle is extremely straightforward and sql-like. See for yourself:

<Section>
```typescript copy 
await db.insert(users).values({ name: 'Andrew' });
```

```sql
insert into [users] ([name], [age]) values ('Andrew', default)
```
</Section>

If you need insert type for a particular table you can use `typeof usersTable.$inferInsert` syntax. 
```typescript copy 
type NewUser = typeof users.$inferInsert;

const insertUser = async (user: NewUser) => {
  return db.insert(users).values(user);
}

const newUser: NewUser = { name: "Alef" };
await insertUser(newUser);
```

## Insert with output
MSSQL supports the `OUTPUT` clause for returning inserted rows. Drizzle exposes it through the `.output()` method.

```typescript copy
const result = await db
  .insert(usersTable)
  .output({ id: usersTable.id })
  .values([{ name: 'John' }, { name: 'John1' }]);
//    ^? { id: number }[]
```

You can also return all inserted columns by calling `.output()` without arguments.

```ts
const result = await db.insert(usersTable).output().values({ name: 'John' });
//    ^? typeof usersTable.$inferSelect[]
```

## Insert multiple rows
```typescript copy
await db.insert(users).values([{ name: 'Andrew' }, { name: 'Dan' }]);
```

## Upserts and conflicts
MSSQL does not support PostgreSQL-style `ON CONFLICT` or MySQL-style `ON DUPLICATE KEY UPDATE` clauses. For upsert workflows, use a transaction with explicit `select`/`update`/`insert` logic or execute a dialect-specific `MERGE` statement with the `sql` operator.

## Insert into ... select

Currently not supported

Source: https://orm.drizzle.team/docs/mssql/joins

import CodeTabs from '@mdx/CodeTabs.astro';
import CodeTab from '@mdx/CodeTab.astro';
import Section from '@mdx/Section.astro';

# Joins [SQL]
Join clause in SQL is used to combine 2 or more tables, based on related columns between them.
Drizzle ORM joins syntax is a balance between the SQL-likeness and type safety.

## Join types
Drizzle ORM has APIs for `INNER JOIN`, `LEFT JOIN`, `RIGHT JOIN`, and `FULL JOIN`.
Lets have a quick look at examples based on below table schemas:
```typescript copy
export const users = mssqlTable('users', {
  id: int().primaryKey().identity(),
  name: varchar({ length: 255 }).notNull(),
});

export const pets = mssqlTable('pets', {
  id: int().primaryKey().identity(),
  name: varchar({ length: 255 }).notNull(),
  ownerId: int('owner_id').notNull().references(() => users.id),
})
```

### Left Join
<Section>
```typescript copy
const result = await db.select().from(users).leftJoin(pets, eq(users.id, pets.ownerId))
```
```sql
select ... from [users] left join [pets] on [users].[id] = [pets].[owner_id]
```
```typescript
// result type
const result: {
    user: {
        id: number;
        name: string;
    };
    pets: {
        id: number;
        name: string;
        ownerId: number;
    } | null;
}[];
```
</Section>


### Right Join
<Section>
```typescript copy
const result = await db.select().from(users).rightJoin(pets, eq(users.id, pets.ownerId))
```
```sql
select ... from [users] right join [pets] on [users].[id] = [pets].[owner_id]
```
```typescript
// result type
const result: {
    user: {
        id: number;
        name: string;
    } | null;
    pets: {
        id: number;
        name: string;
        ownerId: number;
    };
}[];
```
</Section>

### Inner Join
<Section>
```typescript copy
const result = await db.select().from(users).innerJoin(pets, eq(users.id, pets.ownerId))
```
```sql
select ... from [users] inner join [pets] on [users].[id] = [pets].[owner_id]
```
```typescript
// result type
const result: {
    user: {
        id: number;
        name: string;
    };
    pets: {
        id: number;
        name: string;
        ownerId: number;
    };
}[];
```
</Section>



### Full Join
<Section>
```typescript copy
const res = await db.select().from(users).fullJoin(pets, eq(users.id, pets.ownerId));
```
```sql
select ... from [users] full join [pets] on [users].[id] = [pets].[owner_id]
```
```typescript
// result type
const result: {
    users: {
        id: number;
        name: string;
    } | null;
    pets: {
        id: number;
        name: string;
        ownerId: number;
    } | null;
}[];
```
</Section>


## Partial select
If you need to select a particular subset of fields or to have a flat response type, Drizzle ORM
supports joins with partial select and will automatically infer return type based on `.select({ ... })` structure.
<Section>
```typescript copy
await db.select({
  userId: users.id,
  petId: pets.id,
}).from(users).leftJoin(pets, eq(users.id, pets.ownerId))
```
```sql
select [users].[id], [pets].[id] from [users] left join [pets] on [users].[id] = [pets].[owner_id]
```
```typescript
// result type
const result: {
  userId: number;
  petId: number | null;
}[];
```
</Section>
You might've noticed that `petId` can be null now, it's because we're left joining and there can be users without a pet.

It's very important to keep in mind when using `sql` operator for partial selection fields and aggregations when needed,
you should to use `sql<type | null>` for proper result type inference, that one is on you!
<Section>
```typescript copy
const result = await db.select({
  userId: users.id,
  petId: pets.id,
  petName1: sql`upper(${pets.name})`,
  petName2: sql<string | null>`upper(${pets.name})`,
  //˄we should explicitly tell 'string | null' in type, since we're left joining that field
}).from(users).leftJoin(pets, eq(users.id, pets.ownerId))
```
```sql
select [users].[id], [pets].[id], upper([pets].[name])... from [users] left join [pets] on [users].[id] = [pets].[owner_id]
```
```typescript
// result type
const result: {
  userId: number;
  petId: number | null;
  petName1: unknown;
  petName2: string | null;
}[];
```
</Section>
To avoid plethora of nullable fields when joining tables with lots of columns we can utilise our **nested select object syntax**,
our smart type inference will make whole object nullable instead of making all table fields nullable!
<Section>
```typescript copy
await db.select({
  userId: users.id,
  userName: users.name,
  pet: {
    id: pets.id,
    name: pets.name,
    upperName: sql<string>`upper(${pets.name})`
  }
}).from(users).leftJoin(pets, eq(users.id, pets.ownerId))
```
```sql
select ... from [users] left join [pets] on [users].[id] = [pets].[owner_id]
```
```typescript
// result type
const result: {
    userId: number;
    userName: string;
    pet: {
        id: number;
        name: string;
        upperName: string;
    } | null;
}[];
```
</Section>

## Aliases & Selfjoins
Drizzle ORM supports table aliases which comes really handy when you need to do selfjoins.

Lets say you need to fetch users with their parents:
<CodeTabs items={["index.ts", "schema.ts"]}>
<CodeTab>
```typescript copy
import { user } from "./schema";

const parent = alias(user, "parent");
const result = await db
  .select()
  .from(user)
  .leftJoin(parent, eq(parent.id, user.parentId));
```
```sql
select ... from [user] left join [user] [parent] on [parent].[id] = [user].[parent_id]
```
```typescript
// result type
const result: {
    user: {
        id: number;
        name: string;
        parentId: number;
    };
    parent: {
        id: number;
        name: string;
        parentId: number;
    } | null;
}[];
```
</CodeTab>

```typescript
export const user = mssqlTable("user", {
  id: int().primaryKey().identity(),
  name: varchar({ length: 255 }).notNull(),
  parentId: int("parent_id").notNull().references((): MsSqlColumn => user.id)
});
```

</CodeTabs>

## Aggregating results
Drizzle ORM delivers name-mapped results from the driver without changing the structure.

You're free to operate with results the way you want, here's an example of mapping many-one relational data:
```typescript
type User = typeof users.$inferSelect;
type Pet = typeof pets.$inferSelect;

const rows = await db.select({
    user: users,
    pet: pets,
  }).from(users).leftJoin(pets, eq(users.id, pets.ownerId));

const result = rows.reduce<Record<number, { user: User; pets: Pet[] }>>(
  (acc, row) => {
    const user = row.user;
    const pet = row.pet;

    if (!acc[user.id]) {
      acc[user.id] = { user, pets: [] };
    }

    if (pet) {
      acc[user.id]!.pets.push(pet);
    }

    return acc;
  },
  {}
);

// result type
const result: Record<number, {
    user: User;
    pets: Pet[];
}>;
```

## Many-to-one example
```typescript
import { mssqlTable, varchar, int } from 'drizzle-orm/mssql-core';
import { drizzle } from 'drizzle-orm/node-mssql';

const cities = mssqlTable('cities', {
  id: int().primaryKey().identity(),
  name: varchar({ length: 255 }),
});

const users = mssqlTable('users', {
  id: int().primaryKey().identity(),
  name: varchar({ length: 255 }),
  cityId: int('city_id').references(() => cities.id)
});

const db = drizzle();

const result = await db.select().from(cities).leftJoin(users, eq(cities.id, users.cityId));
```
## Many-to-many example
```typescript
const users = mssqlTable('users', {
  id: int().primaryKey().identity(),
  name: varchar({ length: 255 }),
});

const chatGroups = mssqlTable('chat_groups', {
  id: int().primaryKey().identity(),
  name: varchar({ length: 255 }),
});

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


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


Source: https://orm.drizzle.team/docs/mssql/kit-custom-migrations

import CodeTab from '@mdx/CodeTab.astro';
import CodeTabs from '@mdx/CodeTabs.astro';
import Section from '@mdx/Section.astro';
import Tab from '@mdx/Tab.astro';
import Tabs from '@mdx/Tabs.astro';
import Callout from '@mdx/Callout.astro';
import Npm from '@mdx/Npm.astro';
import Npx from '@mdx/Npx.astro';
import Steps from '@mdx/Steps.astro';
import Prerequisites from "@mdx/Prerequisites.astro"

# Migrations with Drizzle Kit
<Prerequisites>
- Get started with Drizzle and `drizzle-kit` - [read here](/docs/mssql/get-started)
- Drizzle schema fundamentals - [read here](/docs/mssql/sql-schema-declaration)
- Database connection basics - [read here](/docs/mssql/connect-overview)
- Drizzle migrations fundamentals - [read here](/docs/mssql/migrations)
- Drizzle Kit [overview](/docs/mssql/kit-overview) and [config file](/docs/mssql/drizzle-config-file)
- `drizzle-kit generate` command - [read here](/docs/mssql/drizzle-kit-generate)
- `drizzle-kit migrate` command - [read here](/docs/mssql/drizzle-kit-migrate)
</Prerequisites>

Drizzle lets you generate empty migration files to write your own custom SQL migrations 
for DDL alternations currently not supported by Drizzle Kit or data seeding, which you can then run with [`drizzle-kit migrate`](/docs/mssql/drizzle-kit-migrate) command.

```shell
drizzle-kit generate --custom --name=seed-users
```
<Section>
```plaintext {4}
📦 <project root>
 ├ 📂 drizzle
 │ ├ 📂 20242409125510_init_sql
 │ └ 📂 20242409135510_seed-users
 ├ 📂 src
 └ …
```
```sql
-- ./drizzle/20242409135510_seed-users.sql

INSERT INTO [users] ([name]) VALUES('Dan');
INSERT INTO [users] ([name]) VALUES('Andrew');
INSERT INTO [users] ([name]) VALUES('Dandrew');
```
</Section>

### Running JavaScript and TypeScript migrations
We will add ability to run custom JavaScript and TypeScript migration/seeding scripts in the upcoming release, you can follow [github discussion](https://github.com/drizzle-team/drizzle-orm/discussions/2832).

Source: https://orm.drizzle.team/docs/mssql/kit-overview

import CodeTab from '@mdx/CodeTab.astro';
import CodeTabs from '@mdx/CodeTabs.astro';
import Section from '@mdx/Section.astro';
import Tab from '@mdx/Tab.astro';
import Tabs from '@mdx/Tabs.astro';
import Callout from '@mdx/Callout.astro';
import Npm from '@mdx/Npm.astro';
import Npx from '@mdx/Npx.astro';
import Steps from '@mdx/Steps.astro';
import Prerequisites from "@mdx/Prerequisites.astro"

# Migrations with Drizzle Kit
<Prerequisites>
- Get started with Drizzle and `drizzle-kit` - [read here](/docs/mssql/get-started)
- Drizzle schema fundamentals - [read here](/docs/mssql/sql-schema-declaration)
- Database connection basics - [read here](/docs/mssql/connect-overview)
- Drizzle migrations fundamentals - [read here](/docs/mssql/migrations)
</Prerequisites>


**Drizzle Kit** is a CLI tool for managing SQL database migrations with Drizzle.
<Npm>
  -D drizzle-kit
</Npm>
<Callout type="warning">
Make sure to first go through Drizzle [get started](/docs/mssql/get-started) and [migration fundamentals](/docs/mssql/migrations) and pick SQL migration flow that suits your business needs best. 
</Callout>

Based on your schema, Drizzle Kit let's you generate and run SQL migration files, 
push schema directly to the database, pull schema from database, spin up drizzle studio and has a couple of utility commands.
<Npx>
drizzle-kit generate
drizzle-kit migrate
drizzle-kit push
drizzle-kit pull
drizzle-kit check
drizzle-kit up
drizzle-kit studio
drizzle-kit export
</Npx>


|                                                      |                                                                                                                                                                    |
| :--------------------------------------------------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| [`drizzle-kit generate`](/docs/mssql/drizzle-kit-generate) | lets you generate SQL migration files based on your Drizzle schema either upon declaration or on subsequent changes, [see here](/docs/mssql/drizzle-kit-generate).       |
| [`drizzle-kit migrate`](/docs/mssql/drizzle-kit-migrate)   | lets you apply generated SQL migration files to your database, [see here](/docs/mssql/drizzle-kit-migrate).                                                              |
| [`drizzle-kit pull`](/docs/mssql/drizzle-kit-pull)         | lets you pull(introspect) database schema, convert it to Drizzle schema and save it to your codebase, [see here](/docs/mssql/drizzle-kit-pull)                           |
| [`drizzle-kit push`](/docs/mssql/drizzle-kit-push)         | lets you push your Drizzle schema to database either upon declaration or on subsequent schema changes, [see here](/docs/mssql/drizzle-kit-push)                          |
| [`drizzle-kit studio`](/docs/mssql/drizzle-kit-studio)     | will connect to your database and spin up proxy server for Drizzle Studio which you can use for convenient database browsing, [see here](/docs/mssql/drizzle-kit-studio) |
| [`drizzle-kit check`](/docs/mssql/drizzle-kit-check)       | will walk through all generate migrations and check for any race conditions(collisions) of generated migrations, [see here](/docs/mssql/drizzle-kit-check)               |
| [`drizzle-kit up`](/docs/mssql/drizzle-kit-up)             | used to upgrade snapshots of previously generated migrations, [see here](/docs/mssql/drizzle-kit-up)                                                                     |
| [`drizzle-kit export`](/docs/mssql/drizzle-kit-export)     | used to convert a TypeScript schema into raw SQL DDL and print it out [see here](/docs/mssql/drizzle-kit-export)                                                                     |
<br/>

Drizzle Kit is configured through [drizzle.config.ts](/docs/mssql/drizzle-config-file) configuration file or via CLI params.<br/>
It's required to at least provide SQL `dialect` and `schema` path for Drizzle Kit to know how to generate migrations.
```
📦 <project root>
 ├ 📂 drizzle
 ├ 📂 src
 ├ 📜 .env
 ├ 📜 drizzle.config.ts  <--- Drizzle config file
 ├ 📜 package.json
 └ 📜 tsconfig.json
```

<CodeTabs items={["simple config", "extended config"]}>
```ts
import { defineConfig } from "drizzle-kit";

export default defineConfig({
  dialect: "mssql",
  schema: "./src/schema.ts",
});
```
```ts
import { defineConfig } from "drizzle-kit";

export default defineConfig({
  out: "./drizzle",
  dialect: "mssql",
  schema: "./src/schema.ts",

  dbCredentials: {
    url: "./database/",
  },

  schemaFilter: "dbo",
  tablesFilter: "*",

  introspect: {
    casing: "camel",
  },

  migrations: {
    table: "__drizzle_migrations__",
    schema: "drizzle",
  },

  breakpoints: true,
  verbose: true,
});
```
</CodeTabs>

You can provide Drizzle Kit config path via CLI param, it's very useful when you have multiple database stages or multiple databases or different databases on the same project:

<Npx>
  drizzle-kit push --config=drizzle-dev.drizzle.config
  drizzle-kit push --config=drizzle-prod.drizzle.config
</Npx>
```plaintext {5-6}
📦 <project root>
 ├ 📂 drizzle
 ├ 📂 src
 ├ 📜 .env
 ├ 📜 drizzle-dev.config.ts
 ├ 📜 drizzle-prod.config.ts
 ├ 📜 package.json
 └ 📜 tsconfig.json
```


Source: https://orm.drizzle.team/docs/mssql/migrations

import Callout from '@mdx/Callout.astro';
import Steps from '@mdx/Steps.astro';
import CodeTab from '@mdx/CodeTab.astro';
import CodeTabs from '@mdx/CodeTabs.astro';
import Section from '@mdx/Section.astro';
import Tab from '@mdx/Tab.astro';
import Tabs from '@mdx/Tabs.astro';
import Npm from '@mdx/Npm.astro';
import Tag from '@mdx/Tag.astro'


# Drizzle migrations fundamentals

SQL databases require you to specify a **strict schema** of entities you're going to store upfront 
and if (when) you need to change the shape of those entities - you will need to do it via **schema migrations**.

There're multiple production grade ways of managing database migrations. 
Drizzle is designed to perfectly suits all of them, regardless of you going **database first** or **codebase first**.

**Database first** is when your database schema is a source of truth. You manage your database schema either directly on the database or 
via database migration tools and then you pull your database schema to your codebase application level entities.  
 
**Codebase first** is when database schema in your codebase is a source of truth and is under version control. You declare and manage your database schema in JavaScript/TypeScript
and then you apply that schema to the database itself either with Drizzle, directly or via external migration tools. 

#### How can Drizzle help?
We've built [**drizzle-kit**](/docs/mssql/kit-overview) - CLI app for managing migrations with Drizzle. 
```shell
drizzle-kit migrate
drizzle-kit generate
drizzle-kit push
drizzle-kit pull
drizzle-kit export
```
It is designed to let you choose how to approach migrations based on your current business demands. 

It fits in both database and codebase first approaches, it lets you **push your schema** or **generate SQL migration** files or **pull the schema** from database. 
It is perfect wether you work alone or in a team.
<br/>

<hr/>
<rem/>

**Now let's pick the best option for your project:**
<rem/>

<Tag style="font-size: 12px">**Option 1**</Tag>
> I manage database schema myself using external migration tools or by running SQL migrations directly on my database.
> From Drizzle I just need to get current state of the schema from my database and save it as TypeScript schema file.

<Callout collapsed="Expand details">
That's a **database first** approach. You have your database schema as a **source of truth** and 
Drizzle lets you pull database schema to TypeScript using [`drizzle-kit pull`](/docs/mssql/drizzle-kit-pull) command.

<Section>
```
                                  ┌────────────────────────┐      ┌───────────────────────────────┐ 
                                  │                        │ <---  CREATE TABLE [users] (
┌──────────────────────────┐      │                        │        [id] int identity primary key,
│ ~ drizzle-kit pull       │      │                        │        [name] varchar(255),
└─┬────────────────────────┘      │        DATABASE        │        [email] varchar(255) unique
  │                               │                        │       );
  └ Pull datatabase schema -----> │                        │
  ┌ Generate Drizzle       <----- │                        │
  │ schema TypeScript file        └────────────────────────┘
  │
  v
```
```typescript
import * as p from "drizzle-orm/mssql-core";

export const users = p.mssqlTable("users", {
	id: p.int().identity({ seed: 1 ,increment: 1 }),
	name: p.varchar({ length: 255 }),
	email: p.varchar({ length: 255 }),
}, (table) => [
	p.primaryKey({ columns: [table.id], name: "PK__users__3213E83FFAA14405"}),
	p.unique("UQ__users__AB6E6164E0557A2A").on(table.email)
]);
```
</Section>
</Callout>

<rem/>
<rem/>
<rem/>

<Tag style="font-size: 12px">**Option 2**</Tag>
> I want to have database schema in my TypeScript codebase, 
> I don't wanna deal with SQL migration files.  
> I want Drizzle to "push" my schema directly to the database

<Callout collapsed="Expand details">
That's a **codebase first** approach. You have your TypeScript Drizzle schema as a **source of truth** and 
Drizzle lets you push schema changes to the database using [`drizzle-kit push`](/docs/mssql/drizzle-kit-push) command.

That's the best approach for rapid prototyping and we've seen dozens of teams 
and solo developers successfully using it as a primary migrations flow in their production applications.

<Section>
```typescript {6} filename="src/schema.ts"
import * as p from "drizzle-orm/mssql-core";

export const users = p.mssqlTable("users", {
  id: p.int().primaryKey().identity(),
  name: p.varchar({ length: 255 }),
  email: p.varchar({ length: 255 }).unique(), // <--- added column
});
```
```
Add column to `users` table                                                                          
┌────────────────────────────────────────────┐                  
│ + email: varchar({ length: 255 }).unique() │                  
└─┬──────────────────────────────────────────┘                  
  │                                           
  v                                           
┌──────────────────────────┐                  
│ ~ drizzle-kit push       │                  
└─┬────────────────────────┘                  
  │                                           ┌──────────────────────────┐
  └ Pull current datatabase schema ---------> │                          │
                                              │                          │
  ┌ Generate alternations based on diff <---- │         DATABASE         │
  │                                           │                          │
  └ Apply migrations to the database -------> │                          │
                                       │      └──────────────────────────┘
                                       │
  ┌────────────────────────────────────┴───────────────────────────────┐
   ALTER TABLE [users] ADD [email] varchar(255);
   ALTER TABLE [users] ADD CONSTRAINT [users_email_key] UNIQUE([email]);
```
</Section>
</Callout>

<rem/>
<rem/>
<rem/>

<Tag style="font-size: 12px">**Option 3**</Tag>
> I want to have database schema in my TypeScript codebase, 
> I want Drizzle to generate SQL migration files for me and apply them to my database

<Callout collapsed="Expand details">
That's a **codebase first** approach. You have your TypeScript Drizzle schema as a source of truth and 
Drizzle lets you generate SQL migration files based on your schema changes with [`drizzle-kit generate`](/docs/mssql/drizzle-kit-generate)
and then apply them to the database with [`drizzle-kit migrate`](/docs/mssql/drizzle-kit-migrate) commands. 
<Section>
```typescript filename="src/schema.ts"
import * as p from "drizzle-orm/mssql-core";

export const users = p.mssqlTable("users", {
  id: p.int().primaryKey().identity(),
  name: p.varchar({ length: 255 }),
  email: p.varchar({ length: 255 }).unique(),
});
```
```                                  
┌────────────────────────┐                  
│ $ drizzle-kit generate │                  
└─┬──────────────────────┘                  
  │                                           
  └ 1. read previous migration folders
    2. find diff between current and previous schema
    3. prompt developer for renames if necessary
  ┌ 4. generate SQL migration and persist to file
  │    ┌─┴───────────────────────────────────────┐  
  │      📂 drizzle       
  │      └ 📂 20242409125510_premium_mister_fear
  │        ├ 📜 snapshot.json
  │        └ 📜 migration.sql
  v
```
```sql
-- drizzle/20242409125510_premium_mister_fear/migration.sql

CREATE TABLE [users] (
	[id] int IDENTITY(1, 1),
	[name] varchar(255),
	[email] varchar(255),
	CONSTRAINT [users_pkey] PRIMARY KEY([id]),
	CONSTRAINT [users_email_key] UNIQUE([email])
);
```
```
┌───────────────────────┐                  
│ $ drizzle-kit migrate │                  
└─┬─────────────────────┘                  
  │                                                         ┌──────────────────────────┐                                         
  └ 1. read migration.sql files in migrations folder        │                          │
    2. fetch migration history from database -------------> │                          │
  ┌ 3. pick previously unapplied migrations <-------------- │         DATABASE         │
  └ 4. apply new migration to the database ---------------> │                          │
                                                            │                          │
                                                            └──────────────────────────┘
[✓] done!                                                 
```
</Section>
</Callout>

<rem/>
<rem/>
<rem/>

<Tag style="font-size: 12px">**Option 4**</Tag>
> I want to have database schema in my TypeScript codebase,
> I want Drizzle to generate SQL migration files for me and I want Drizzle to apply them during runtime

<Callout collapsed="Expand details">
That's a **codebase first** approach. You have your TypeScript Drizzle schema as a source of truth and 
Drizzle lets you generate SQL migration files based on your schema changes with [`drizzle-kit generate`](/docs/mssql/drizzle-kit-generate) and then 
you can apply them to the database during runtime of your application.

This approach is widely used for **monolithic** applications when you apply database migrations 
during zero downtime deployment and rollback DDL changes if something fails. 
This is also used in **serverless** deployments with migrations running in **custom resource** once during deployment process.

<Section>
```typescript filename="src/schema.ts"
import * as p from "drizzle-orm/mssql-core";

export const users = p.mssqlTable("users", {
  id: p.int().primaryKey().identity(),
  name: p.varchar({ length: 255 }),
  email: p.varchar({ length: 255 }).unique(),
});
```
```                                  
┌────────────────────────┐                  
│ $ drizzle-kit generate │                  
└─┬──────────────────────┘                  
  │                                           
  └ 1. read previous migration folders
    2. find diff between current and previous schema
    3. prompt developer for renames if necessary
  ┌ 4. generate SQL migration and persist to file
  │    ┌─┴───────────────────────────────────────┐  
  │      📂 drizzle       
  │      └ 📂 20242409125510_premium_mister_fear
  │        ├ 📜 snapshot.json
  │        └ 📜 migration.sql
  v
```
```sql
-- drizzle/20242409125510_premium_mister_fear/migration.sql

CREATE TABLE [users] (
	[id] int IDENTITY(1, 1),
	[name] varchar(255),
	[email] varchar(255),
	CONSTRAINT [users_pkey] PRIMARY KEY([id]),
	CONSTRAINT [users_email_key] UNIQUE([email])
);
```
```ts
// index.ts
import { drizzle } from "drizzle-orm/node-mssql"
import { migrate } from 'drizzle-orm/node-mssql/migrator';

const db = drizzle(process.env.DATABASE_URL);

await migrate(db);
```
```
┌───────────────────────┐                  
│ npx tsx src/index.ts  │                  
└─┬─────────────────────┘                  
  │                                                      
  ├ 1. init database connection                             ┌──────────────────────────┐                                         
  └ 2. read migration.sql files in migrations folder        │                          │
    3. fetch migration history from database -------------> │                          │
  ┌ 4. pick previously unapplied migrations <-------------- │         DATABASE         │
  └ 5. apply new migration to the database ---------------> │                          │
                                                            │                          │
                                                            └──────────────────────────┘
[✓] done!                                                 
```
</Section>
</Callout>

<rem/>
<rem/>
<rem/>

<Tag style="font-size: 12px">**Option 5**</Tag>
> I want to have database schema in my TypeScript codebase,
> I want Drizzle to generate SQL migration files for me,
> but I will apply them to my database myself or via external migration tools 

<Callout collapsed="Expand details">
That's a **codebase first** approach. You have your TypeScript Drizzle schema as a source of truth and 
Drizzle lets you generate SQL migration files based on your schema changes with [`drizzle-kit generate`](/docs/mssql/drizzle-kit-generate) and then 
you can apply them to the database either directly or via external migration tools.

<Section>
```typescript filename="src/schema.ts"
import * as p from "drizzle-orm/mssql-core";

export const users = p.mssqlTable("users", {
  id: p.int().primaryKey().identity(),
  name: p.varchar({ length: 255 }),
  email: p.varchar({ length: 255 }).unique(),
});
```
```                                  
┌────────────────────────┐                  
│ $ drizzle-kit generate │                  
└─┬──────────────────────┘                  
  │                                           
  └ 1. read previous migration folders
    2. find diff between current and previous scheama
    3. prompt developer for renames if necessary
  ┌ 4. generate SQL migration and persist to file
  │    ┌─┴───────────────────────────────────────┐  
  │      📂 drizzle       
  │      └ 📂 20242409125510_premium_mister_fear
  │        ├ 📜 snapshot.json
  │        └ 📜 migration.sql
  v
```
```sql
-- drizzle/20242409125510_premium_mister_fear/migration.sql

CREATE TABLE [users] (
	[id] int IDENTITY(1, 1),
	[name] varchar(255),
	[email] varchar(255),
	CONSTRAINT [users_pkey] PRIMARY KEY([id]),
	CONSTRAINT [users_email_key] UNIQUE([email])
);
```
```
┌───────────────────────────────────┐                  
│ (._.) now you run your migrations │           
└─┬─────────────────────────────────┘  
  │
 directly to the database
  │                                         ┌────────────────────┐
  ├────────────────────────────────────┬───>│                    │  
  │                                    │    │      Database      │           
 or via external tools                 │    │                    │   
  │                                    │    └────────────────────┘
  │  ┌────────────────────┐            │      
  └──│ Bytebase           ├────────────┘         
     ├────────────────────┤  
     │ Liquibase          │
     ├────────────────────┤ 
     │ Atlas              │
     ├────────────────────┤ 
     │ etc…               │
     └────────────────────┘

[✓] done!                                                 
```
</Section>
</Callout>

<rem/>
<rem/>
<rem/>

<Tag style="font-size: 12px">**Option 6**</Tag>
> I want to have database schema in my TypeScript codebase,
> I want Drizzle to output the SQL representation of my Drizzle schema to the console,
> and I will apply them to my database via [Atlas](https://atlasgo.io/guides/orms/drizzle)

<Callout collapsed="Expand details">
That's a **codebase first** approach. You have your TypeScript Drizzle schema as a source of truth and 
Drizzle lets you export SQL statements based on your schema changes with [`drizzle-kit export`](/docs/mssql/drizzle-kit-generate) and then 
you can apply them to the database via [Atlas](https://atlasgo.io/guides/orms/drizzle) or other external SQL migration tools.

<Section>
```typescript filename="src/schema.ts"
import * as p from "drizzle-orm/mssql-core";

export const users = p.mssqlTable("users", {
  id: p.int().primaryKey().identity(),
  name: p.varchar({ length: 255 }),
  email: p.varchar({ length: 255 }).unique(),
});
```
```                                  
┌────────────────────────┐                  
│ $ drizzle-kit export   │                  
└─┬──────────────────────┘                  
  │                                           
  └ 1. read your drizzle schema
    2. generated SQL representation of your schema
  ┌ 3. outputs to console
  │    
  │        
  v
```
```sql
CREATE TABLE [users] (
	[id] int IDENTITY(1, 1),
	[name] varchar(255),
	[email] varchar(255),
	CONSTRAINT [users_pkey] PRIMARY KEY([id]),
	CONSTRAINT [users_email_key] UNIQUE([email])
);
```
```
┌───────────────────────────────────┐                  
│ (._.) now you run your migrations │           
└─┬─────────────────────────────────┘  
  │
 via Atlas
  │                                    ┌──────────────┐
  │  ┌────────────────────┐            │              │
  └──│ Atlas              ├───────────>│  Database    │      
     └────────────────────┘            │              │       
                                       └──────────────┘

[✓] done!                                                 
```
</Section>
</Callout>

<rem/>
<rem/>


Source: https://orm.drizzle.team/docs/mssql/operators

import Section from '@mdx/Section.astro';
import Callout from "@mdx/Callout.astro";

# Filter and conditional operators

<Callout type='info'>
All the values provided to filter operators and to the `sql` function are parameterized automatically.
For example, this query:
```ts
await db.select().from(users).where(eq(users.id, 42));
```
will be translated to:
```sql
select [id], [name], [age] from [users] where [users].[id] = @par0; -- params: [42]
```
</Callout>

<br/>

We natively support all dialect specific filter and conditional operators.

You can import all filter & conditional from `drizzle-orm`:
```typescript copy
import { eq, ne, gt, gte, ... } from "drizzle-orm";
```

### eq

  
Value equal to `n`
<Section>
```typescript copy
import { eq } from "drizzle-orm";

db.select().from(table).where(eq(table.column, 5));
```

```sql copy
SELECT * FROM [table] WHERE [table].[column] = 5
```
</Section>

<Section>
```typescript
import { eq } from "drizzle-orm";

db.select().from(table).where(eq(table.column1, table.column2));
```

```sql
SELECT * FROM [table] WHERE [table].[column1] = [table].[column2]
```
</Section>

### ne

  
Value is not equal to `n`  
<Section>
```typescript
import { ne } from "drizzle-orm";

db.select().from(table).where(ne(table.column, 5));
```

```sql
SELECT * FROM [table] WHERE [table].[column] <> 5
```
</Section>

<Section>
```typescript
import { ne } from "drizzle-orm";

db.select().from(table).where(ne(table.column1, table.column2));
```

```sql
SELECT * FROM [table] WHERE [table].[column1] <> [table].[column2]
```
</Section>

## ---

### gt
 
  
Value is greater than `n`
<Section>
```typescript
import { gt } from "drizzle-orm";

db.select().from(table).where(gt(table.column, 5));
```

```sql
SELECT * FROM [table] WHERE [table].[column] > 5
```
</Section>

<Section>
```typescript
import { gt } from "drizzle-orm";

db.select().from(table).where(gt(table.column1, table.column2));
```

```sql
SELECT * FROM [table] WHERE [table].[column1] > [table].[column2]
```
</Section>

### gte

  
Value is greater than or equal to `n`
<Section>
```typescript
import { gte } from "drizzle-orm";

db.select().from(table).where(gte(table.column, 5));
```

```sql
SELECT * FROM [table] WHERE [table].[column] >= 5
```
</Section>

<Section>
```typescript
import { gte } from "drizzle-orm";

db.select().from(table).where(gte(table.column1, table.column2));
```

```sql
SELECT * FROM [table] WHERE [table].[column1] >= [table].[column2]
```
</Section>

### lt

  
Value is less than `n`
<Section>
```typescript
import { lt } from "drizzle-orm";

db.select().from(table).where(lt(table.column, 5));
```

```sql
SELECT * FROM [table] WHERE [table].[column] < 5
```
</Section>

<Section>
```typescript
import { lt } from "drizzle-orm";

db.select().from(table).where(lt(table.column1, table.column2));
```

```sql
SELECT * FROM [table] WHERE [table].[column1] < [table].[column2]
```
</Section>

### lte

  
Value is less than or equal to `n`.

<Section>
```typescript
import { lte } from "drizzle-orm";

db.select().from(table).where(lte(table.column, 5));
```

```sql
SELECT * FROM [table] WHERE [table].[column] <= 5
```
</Section>

<Section>
```typescript
import { lte } from "drizzle-orm";

db.select().from(table).where(lte(table.column1, table.column2));
```

```sql
SELECT * FROM [table] WHERE [table].[column1] <= [table].[column2]
```
</Section>

## ---

### exists

  
Value exists
<Section>
```typescript
import { exists } from "drizzle-orm";

const query = db.select().from(table2)
db.select().from(table).where(exists(query));
```

```sql
SELECT * FROM [table] WHERE EXISTS (SELECT * FROM [table2])
```
</Section>

### notExists

<Section>
```typescript
import { notExists } from "drizzle-orm";

const query = db.select().from(table2)
db.select().from(table).where(notExists(query));
```

```sql
SELECT * FROM [table] WHERE NOT EXISTS (SELECT * FROM [table2])
```
</Section>

### isNull
  
Value is `null`
<Section>
```typescript
import { isNull } from "drizzle-orm";

db.select().from(table).where(isNull(table.column));
```

```sql
SELECT * FROM [table] WHERE ([table].[column] IS NULL)
```
</Section>

### isNotNull

  
Value is not `null`
<Section>
```typescript
import { isNotNull } from "drizzle-orm";

db.select().from(table).where(isNotNull(table.column));
```

```sql
SELECT * FROM [table] WHERE ([table].[column] IS NOT NULL)
```
</Section>

## ---

### inArray

  
Value is in array of values
<Section>
```typescript
import { inArray } from "drizzle-orm";

db.select().from(table).where(inArray(table.column, [1, 2, 3, 4]));
```

```sql
SELECT * FROM [table] WHERE [table].[column] IN (1, 2, 3, 4)
```
</Section>

<Section>
```typescript
import { inArray } from "drizzle-orm";

const query = db.select({ data: table2.column }).from(table2);
db.select().from(table).where(inArray(table.column, query));
```

```sql
SELECT * FROM [table] WHERE [table].[column] IN (SELECT [table2].[column] FROM [table2])
```
</Section>

### notInArray

  
Value is not in array of values
<Section>
```typescript
import { notInArray } from "drizzle-orm";

db.select().from(table).where(notInArray(table.column, [1, 2, 3, 4]));
```

```sql
SELECT * FROM [table] WHERE [table].[column] NOT IN (1, 2, 3, 4)
```
</Section>

<Section>
```typescript
import { notInArray } from "drizzle-orm";

const query = db.select({ data: table2.column }).from(table2);
db.select().from(table).where(notInArray(table.column, query));
```

```sql
SELECT * FROM [table] WHERE [table].[column] NOT IN (SELECT [table2].[column] FROM [table2])
```
</Section>

## ---

### between

  
Value is between two values
<Section>
```typescript
import { between } from "drizzle-orm";

db.select().from(table).where(between(table.column, 2, 7));
```

```sql
SELECT * FROM [table] WHERE [table].[column] BETWEEN 2 AND 7
```
</Section>

### notBetween

  
Value is not between two value
<Section>
```typescript
import { notBetween } from "drizzle-orm";

db.select().from(table).where(notBetween(table.column, 2, 7));
```

```sql
SELECT * FROM [table] WHERE [table].[column] NOT BETWEEN 2 AND 7
```
</Section>

## ---

### like

  
Value is like other value, case sensitive
<Section>
```typescript
import { like } from "drizzle-orm";

db.select().from(table).where(like(table.column, "%llo wor%"));
```

```sql
SELECT * FROM [table] WHERE [table].[column] LIKE '%llo wor%'
```
</Section>

### notLike

  
Value is not like other value, case sensitive
<Section>
```typescript
import { notLike } from "drizzle-orm";

db.select().from(table).where(notLike(table.column, "%llo wor%"));
```

```sql
SELECT * FROM [table] WHERE [table].[column] NOT LIKE '%llo wor%'
```
</Section>

## ---

### not

  
All conditions must return `false`.

<Section>
```typescript
import { eq, not } from "drizzle-orm";

db.select().from(table).where(not(eq(table.column, 5)));
```

```sql
SELECT * FROM [table] WHERE NOT ([table].[column] = 5)
```
</Section>

### and

  
All conditions must return `true`.

<Section>
```typescript
import { gt, lt, and } from "drizzle-orm";

db.select().from(table).where(and(gt(table.column, 5), lt(table.column, 7)));
```

```sql
SELECT * FROM [table] WHERE ([table].[column] > 5 AND [table].[column] < 7)
```
</Section>

### or

  
One or more conditions must return `true`.

<Section>
```typescript
import { gt, lt, or } from "drizzle-orm";

db.select().from(table).where(or(gt(table.column, 5), lt(table.column, 7)));
```

```sql
SELECT * FROM [table] WHERE ([table].[column] > 5 OR [table].[column] < 7)
```
</Section>


Source: https://orm.drizzle.team/docs/mssql/overview

import Callout from '@mdx/Callout.astro';
import CodeTabs from '@mdx/CodeTabs.astro';
import YoutubeCards from '@mdx/YoutubeCards.astro';
import GetStartedLinks from '@mdx/GetStartedLinks/index.astro'

# Drizzle ORM

Drizzle ORM is a headless TypeScript ORM with a head. 🐲
> Drizzle is a good friend who's there for you when necessary and doesn't bother when you need some space.

It looks and feels simple, performs on day _1000_ of your project,\
lets you do things your way, and is there when you need it.

**It's the only ORM with both [relational](/docs/mssql/rqb) and [SQL-like](/docs/mssql/select) query APIs**, 
providing you the best of both worlds when it comes to accessing your relational data. 
Drizzle is lightweight, performant, typesafe, non-lactose, gluten-free, sober, flexible and **serverless-ready by design**.
Drizzle is not just a library, it's an experience. 🤩

[![Drizzle bestofjs](@/assets/images/bestofjs.jpg)](https://bestofjs.org/projects/drizzle-orm)

## Headless ORM? 
First and foremost, Drizzle is a library and a collection of complementary opt-in tools. 

**ORM** stands for _object relational mapping_, and developers tend to call Django-like or Spring-like tools an ORM. 
We truly believe it's a misconception based on legacy nomenclature, and we call them **data frameworks**.

<Callout type="error" emoji="️💔">
  With data frameworks you have to build projects **around them** and not **with them**.
</Callout>

**Drizzle** lets you build your project the way you want, without interfering with your project or structure. 

Using Drizzle you can define and manage database schemas in TypeScript, access your data in a SQL-like 
or relational way, and take advantage of opt-in tools 
to push your developer experience _through the roof_. 🤯 

## Why SQL-like?
**If you know SQL, you know Drizzle.**

Other ORMs and data frameworks tend to deviate/abstract you away from SQL, which 
leads to a double learning curve: needing to know both SQL and the framework's API.  

Drizzle is the opposite. 
We embrace SQL and built Drizzle to be SQL-like at its core, so you can have zero to no 
learning curve and access to the full power of SQL.  

We bring all the familiar **[SQL schema](/docs/mssql/sql-schema-declaration)**, **[queries](/docs/mssql/select)**, 
**[automatic migrations](/docs/mssql/migrations)** and **[one more thing](/docs/mssql/rqb)**. ✨

<CodeTabs items={["index.ts", "schema.ts", "migration.sql"]}>
```typescript copy
// Access your data
await db
	.select()
	.from(countries)
	.leftJoin(cities, eq(cities.countryId, countries.id))
	.where(eq(countries.id, 10))
```
```typescript copy
// manage your schema
export const countries = mssqlTable('countries', {
  id: int().primaryKey().identity(),
  name: varchar({ length: 256 }),
});

export const cities = mssqlTable('cities', {
  id: int().primaryKey().identity(),
  name: varchar({ length: 256 }),
  countryId: int('country_id').references(() => countries.id),
});
```
```sql
CREATE TABLE [countries] (
	[id] int IDENTITY(1, 1),
	[name] varchar(256),
	CONSTRAINT [countries_pkey] PRIMARY KEY([id])
);

CREATE TABLE [cities] (
	[id] int IDENTITY(1, 1),
	[name] varchar(256),
	[country_id] int,
	CONSTRAINT [cities_pkey] PRIMARY KEY([id])
);

ALTER TABLE [cities] ADD CONSTRAINT [cities_country_id_countries_id_fk] FOREIGN KEY ([country_id]) REFERENCES [countries]([id]);
```
</CodeTabs>

## Why not SQL-like?
We're always striving for a perfectly balanced solution, and while SQL-like does cover 100% of the needs, 
there are certain common scenarios where you can query data in a better way.  

We've built the **[Queries API](/docs/mssql/rqb)** for you, so you can fetch relational nested data from the database 
in the most convenient and performant way, and never think about joins and data mapping.  

**Drizzle always outputs exactly 1 SQL query.** Feel free to use it with serverless databases and never worry about performance or roundtrip costs!

```ts
const result = await db._query.users.findMany({
	with: {
		posts: true
	},
});
```

## Serverless?
<Callout type="info" emoji="🥳">
  The best part is no part. **Drizzle has exactly 0 dependencies!**
</Callout>


![Drizzle is slim an Serverless ready](@/assets/images/drizzle31kb.jpg)
  
Drizzle ORM is dialect-specific, slim, performant and serverless-ready **by design**.  

We've spent a lot of time to make sure you have best-in-class SQL dialect support, including Postgres, MySQL, and others.

Drizzle operates natively through industry-standard database drivers. We support all major **[PostgreSQL](/docs/get-started-postgresql)**, **[MySQL](/docs/mysql/get-started-mysql)**, **[SQLite](/docs/sqlite/get-started-sqlite)**, **[SingleStore](/docs/singlestore/get-started-singlestore)**, **[MSSQL](/docs/mssql/get-started-mssql)** or **[CockroachDB](/docs/cockroach/get-started-cockroach)** drivers out there, and we're adding new ones **[really fast](https://twitter.com/DrizzleORM/status/1653082492742647811?s=20)**.  


## Welcome on board!
More and more companies are adopting Drizzle in production, experiencing immense benefits in both DX and performance.

**We're always there to help, so don't hesitate to reach out. We'll gladly assist you in your Drizzle journey!**

We have an outstanding **[Discord community](https://driz.link/discord)** and welcome all builders to our **[Twitter](https://twitter.com/drizzleorm)**.
  
Now go build something awesome with Drizzle and your **[PostgreSQL](/docs/get-started-postgresql)**, **[MySQL](/docs/mysql/get-started-mysql)**, **[SQLite](/docs/sqlite/get-started-sqlite)**, **[MSSQL](/docs/mssql/get-started-mssql)** or **[CockroachDB](/docs/cockroach/get-started-cockroach)** database. 🚀

### Video Showcase

{/* tRPC + NextJS App Router = Simple Typesafe APIs
Jack Herrington 19:17
https://www.youtube.com/watch?v=qCLV0Iaq9zU */}
{/* https://www.youtube.com/watch?v=qDunJ0wVIec */}
{/* https://www.youtube.com/watch?v=NZpPMlSAez0 */}

 {/* https://www.youtube.com/watch?v=-A0kMiJqQRY */}

<YoutubeCards cards={[
	{
		id: "vyU5mJGCJMw",
		title: "Full Drizzle Course for Beginners",
		description: "Code Genix",
		time: "1:37:39",
	},
	{
		id: "7-NZ0MlPpJA",
		title: "Learn Drizzle In 60 Minutes",
		description: "Web Dev Simplified",
		time: "56:09"
	},
	{
		id: "i_mAHOhpBSA",
		title: "Drizzle ORM in 100 Seconds",
		description: "Fireship",
		time: "2:55"
	},
	{
		id: "hIYNOiZXQ7Y",
		title: "Learn Drizzle ORM in 13 mins (crash course)",
		description: "Neon",
		time: "14:00"
	},
	{
		id: "4ZhtoOFKFP8",
		title: "Easiest Database Setup in Next.js&nbsp;14 with Turso&nbsp;&&nbsp;Drizzle",
		description: "Sam Meech-Ward",
		time: '38:08'
	}, 
	{
		id: "NfVELsEZFsA",
		title: "Next.js Project with Vercel, Neon, Drizzle, TailwindCSS, FlowBite and more!",
		description: "CodingEntrepreneurs",
		time: '5:46:28'
	}, 
	{
		id: "_SLxGYzv6jo",
		title: "I Have A New Favorite Database&nbsp;Tool",
		description: "Theo - t3.gg",
		time: '5:46'
	}, 
	{
		id: "Qo-RXkSwOtc",
		title: "Drizzle ORM First impressions - migrations, relations, queries!",
		description: "Marius Espejo",
		time: '33:52'
	},
	{
		id: "yXNEqyvA0OY",
		title: "I want to learn Drizzle ORM, so I'm starting another next14 project",
		description: "Web Dev Cody",
		time: "9:00"
	},
	{
		id: "h7vVhR-dFYo",
		title: "Picking an ORM is Getting Harder...",
		description: "Ben Davis",
		time: "5:18"
	},
	{
		id: "8met6WTk0mQ",
		title: "This New Database Tool is a Game-Changer",
		description: "Josh tried coding",
		time: "8:49"
	},
	{
		id: "woWW1T9DXEY",
		title: "My Favorite Database Tool Just Got EVEN Better",
		description: "Josh tried coding",
		time: "4:23"
	},
	{
		id: "A3l6YYkXzzg",
		title: "SaaS Notion Clone with Realtime cursors, Nextjs 13, Stripe, Drizzle ORM, Tailwind, Supabase, Sockets",
		description: "Web Prodigies",
		time: "11:41:46"
	},
	{
		id: "EQfaw5bDE1s",
		title: "SvelteKit + Drizzle Code Breakdown",
		description: "Ben Davis",
		time: "12:18"
	},
	{
		id: "b6VhN_HHDiQ",
		title: "Build a Multi-Tenanted, Role-Based Access Control System",
		description: "TomDoesTech",
		time: "2:01:29"
	},
	/*
	This video became private
	Uncomment (in other files too) it when it becomes public again
	{
		id: "3tl9XCiQErA",
		title: "The Prisma killer is finally here",
		description: "SST",
		time: "5:42"
	},
	*/
	{
		id: "VQFjyEa8vGE",
		title: "Learning Drizzle ORM and working on a next14 project",
		description: "Web Dev Cody",
		time: "1:07:41"
	},
	{
		id: "5G0upg4sxgE",
		title: "This Trick Makes My Favorite Database Tool Even Better",
		description: "Josh tried coding",
		time: "6:01"
	},
	{
		id: "-JnEuvPmt-Q",
		title: "Effortless Auth in Next.js 14: Use Auth.js & Drizzle ORM for Secure Login",
		description: "Sam Meech-Ward",
		time: "26:29"
	},
]} />


Source: https://orm.drizzle.team/docs/mssql/perf-queries

# Query performance
When it comes to **Drizzle** — we're a thin TypeScript layer on top of SQL with 
almost 0 overhead and to make it actual 0, you can utilise our prepared statements API.
  
**When you run a query on the database, there are several things that happen:**
- all the configurations of the query builder got concatenated to the SQL string
- that string and params are sent to the database driver
- driver compiles SQL query to the binary SQL executable format and sends it to the database

With prepared statements you do SQL concatenation once on the Drizzle ORM side and then database 
driver is able to reuse precompiled binary SQL instead of parsing query all the time. 
It has extreme performance benefits on large SQL queries.  

Different database drivers support prepared statements in different ways and sometimes 
Drizzle ORM you can go [**faster than better-sqlite3 driver.**](https://twitter.com/_alexblokh/status/1593593415907909634)

## Prepared statement

```typescript copy {3}
    const db = drizzle(...);

    const prepared = db.select().from(customers).prepare();
    
    const res1 = await prepared.execute();
    const res2 = await prepared.execute();
    const res3 = await prepared.execute();
    ```

## Placeholder
Whenever you need to embed a dynamic runtime value - you can use the `sql.placeholder(...)` api

```ts copy {6,9-10,15,18}
    import { sql } from "drizzle-orm";

    const p1 = db
      .select()
      .from(customers)
      .where(eq(customers.id, sql.placeholder('id')))
      .prepare()

    await p1.execute({ id: 10 }) // SELECT * FROM customers WHERE id = 10
    await p1.execute({ id: 12 }) // SELECT * FROM customers WHERE id = 12

    const p2 = db
      .select()
      .from(customers)
      .where(sql`lower(${customers.name}) like ${sql.placeholder('name')}`)
      .prepare();

    await p2.execute({ name: '%an%' }) // SELECT * FROM customers WHERE lower(name) like '%an%'
    ```


Source: https://orm.drizzle.team/docs/mssql/query-utils

import $count from '@mdx/$count.mdx';

# Drizzle query utils

### $count

Currently not supported

Source: https://orm.drizzle.team/docs/mssql/read-replicas

# Read Replicas

When your project involves a set of read replica instances, and you require a convenient method for managing 
SELECT queries from read replicas, as well as performing create, delete, and update operations on the primary 
instance, you can leverage the `withReplicas()` function within Drizzle

```ts copy
import { drizzle } from "drizzle-orm/node-mssql";
import { ConnectionPool } from "mssql";
import { bit, int, mssqlTable, text, withReplicas } from 'drizzle-orm/mssql-core';

const usersTable = mssqlTable('users', {
	id: int('id').primaryKey().identity(),
	name: text('name').notNull(),
	verified: bit('verified').notNull().default(false),
});

const createClient = async (database: string) => {
  const pool = new ConnectionPool({
    server: "host",
    user: "user",
    password: "password",
    database,
    options: { encrypt: true },
  });

  await pool.connect();
  return pool;
};

const primaryDb = drizzle({ client: await createClient("primary_db") });
const read1 = drizzle({ client: await createClient("read_1") });
const read2 = drizzle({ client: await createClient("read_2") });

const db = withReplicas(primaryDb, [read1, read2]);
```

You can now use the `db` instance the same way you did before. Drizzle will 
handle the choice between read replica and the primary instance automatically

```ts
// Read from either the read1 connection or the read2 connection
await db.select().from(usersTable)

// Use the primary database for the delete operation
await db.delete(usersTable).where(eq(usersTable.id, 1))
```

You can use the `$primary` key to force using primary instances even for read operations

```ts
// read from primary
await db.$primary.select().from(usersTable);
```

With Drizzle, you can also specify custom logic for choosing read replicas. 
You can make a weighted decision or any other custom selection method for random read replica choice. 
Here is an 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 selected.

Keep in mind that you can implement any type of random selection method 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]!
});

await db.select().from(usersTable)
```


Source: https://orm.drizzle.team/docs/mssql/relations-schema-declaration

import Tab from '@mdx/Tab.astro';
import Tabs from '@mdx/Tabs.astro';
import Callout from '@mdx/Callout.astro';
import SimpleLinkCards from '@mdx/SimpleLinkCards.astro';
import CodeTabs from "@mdx/CodeTabs.astro";
import Section from '@mdx/Section.astro';
import Flex from "@mdx/Flex.astro"
import LinksList from "@mdx/LinksList.astro"

# Drizzle Relations Fundamentals

In the world of databases, especially relational databases, the concept of relations is absolutely fundamental.
Think of "relations" as the connections and links between different pieces of data. Just like in real life, 
where people have relationships with each other, or objects are related to categories, databases use relations to model how different 
types of information are connected and work together.

### Normalization
Normalization is the process of organizing data in your database to reduce redundancy (duplication) and improve data integrity 
(accuracy and consistency). Think of it like tidying up a messy filing cabinet. Instead of having all sorts of papers 
crammed into one folder, you organize them into logical folders and categories to make everything easier to find and manage.

<Callout collapsed="Why is Normalization Important?">
- **Reduces Data Redundancy**: Imagine storing a customer's address every time they place an order. If the address changes, you'd have to update it in multiple places! Normalization helps you store information in one place and refer to it from other places, minimizing repetition.
- **Improves Data Integrity**: Less redundancy means less chance of inconsistencies. If you update an address in one place, it's updated everywhere it's needed.
- **Prevents Anomalies**: Normalization helps prevent issues like:
  1. **Insertion Anomalies**: Difficulty adding new data because you're missing related information.
  2. **Update Anomalies**: Having to update the same information in multiple rows.
  3. **Deletion Anomalies**: Accidentally losing valuable information when you delete something seemingly unrelated.
- **Easier to Understand and Maintain**: A normalized database is generally more logically structured and easier to understand, query, and modify.
</Callout>

Normalization is often described in terms of "normal forms" (1NF, 2NF, 3NF, and beyond). While the details can get quite technical, the core ideas are straightforward:

#### 1NF (First Normal Form): `Atomic Values`

**Goal**: Each column should hold a single, indivisible value. No repeating groups of data within a single cell

**Example**: Instead of having a single `address` column that stores `123 Main St, City, USA`, you'd 
break it down into separate columns: `street_address`, `city`, `state`, `zip_code`.

```sql
-- Unnormalized (violates 1NF)
CREATE TABLE [Customers_Unnormalized] (
    [customer_id] INT PRIMARY KEY,
    [name] VARCHAR(255),
    [address] VARCHAR(255) -- Problem: Multiple pieces of info in one column
);

-- Normalized to 1NF
CREATE TABLE [Customers_1NF] (
    [customer_id] INT PRIMARY KEY,
    [name] VARCHAR(255),
    [street_address] VARCHAR(255),
    [city] VARCHAR(255),
    [state] VARCHAR(255),
    [zip_code] VARCHAR(10)
);
```

#### 2NF (Second Normal Form): `Eliminate Redundant Data Dependent on Part of the Key`

**Goal**: Applies when you have a table with a composite primary key (a primary key made up of two or more columns). 
2NF ensures that all non-key attributes are fully dependent on the entire composite primary key, not just part of it.

Imagine we have a table called `order_items`. This table tracks items within orders, and we use a composite primary key (`order_id`, `product_id`) 
because a single order can have multiple of the same product (though in this simplified example, let's assume each product appears only 
once per order for clarity, but the composite key logic still applies).

<Callout collapsed="Expand for visual example">
```sql
CREATE TABLE [OrderItems_Unnormalized] (
    [order_id] INT,
    [product_id] VARCHAR(10),
    [product_name] VARCHAR(100),
    [product_price] DECIMAL(10, 2),
    [quantity] INT,
    [order_date] DATE,
    PRIMARY KEY ([order_id], [product_id]) -- Composite Primary Key
);

INSERT INTO [OrderItems_Unnormalized] ([order_id], [product_id], [product_name], [product_price], [quantity], [order_date]) VALUES
(101, 'A123', 'Laptop', 1200.00, 1, '2023-10-27'),
(101, 'B456', 'Mouse', 25.00, 2, '2023-10-27'),
(102, 'A123', 'Laptop', 1200.00, 1, '2023-10-28'),
(103, 'C789', 'Keyboard', 75.00, 1, '2023-10-29');
```
```
+------------------------------------------------------------------------------------+
| OrderItems_Unnormalized                                                            |
+------------------------------------------------------------------------------------+
| PK (order_id, product_id) | product_name | product_price | quantity | order_date   |
+------------------------------------------------------------------------------------+
| 101, A123               | Laptop       | 1200.00       | 1        | 2023-10-27     |
| 101, B456               | Mouse        | 25.00         | 2        | 2023-10-27     |
| 102, A123               | Laptop       | 1200.00       | 1        | 2023-10-28     |
| 103, C789               | Keyboard     | 75.00         | 1        | 2023-10-29     |
+------------------------------------------------------------------------------------+
```
</Callout>

**Problem**: Notice that `product_name` and `product_price` are repeated whenever the same `product_id` appears in different orders. 
These attributes are only dependent on `product_id`, which is part of the composite primary key (`order_id`, `product_id`), but not the entire key. 
This is a partial dependency.

To achieve 2NF, we need to remove the partially dependent attributes (`product_name`, `product_price`) and place them in a separate table where they are 
fully dependent on the primary key of that new table.

<Callout collapsed="Normalization to 2NF: Visual explanation">
```
+-------------------+     1:M     +---------------------------+
| Products          | <---------- | OrderItems_2NF            |
+-------------------+             +---------------------------+
| PK product_id     |             | PK (order_id, product_id) |
| product_name      |             | quantity                  |
| product_price     |             | order_date                |
+-------------------+             | FK product_id             |
                                  +---------------------------+
```
```sql
CREATE TABLE [Products] (
    [product_id] VARCHAR(10) PRIMARY KEY,
    [product_name] VARCHAR(100),
    [product_price] DECIMAL(10, 2)
);

CREATE TABLE [OrderItems_2NF] (
    [order_id] INT,
    [product_id] VARCHAR(10),
    [quantity] INT,
    [order_date] DATE,
    PRIMARY KEY ([order_id], [product_id]), -- Composite Primary Key remains
    FOREIGN KEY ([product_id]) REFERENCES [Products]([product_id]) -- Foreign Key to Products
);

-- Insert data into Products
INSERT INTO [Products] ([product_id], [product_name], [product_price]) VALUES
('A123', 'Laptop', 1200.00),
('B456', 'Mouse', 25.00),
('C789', 'Keyboard', 75.00);

-- Insert data into OrderItems_2NF (referencing Products)
INSERT INTO [OrderItems_2NF] ([order_id], [product_id], [quantity], [order_date]) VALUES
(101, 'A123', 1, '2023-10-27'),
(101, 'B456', 2, '2023-10-27'),
(102, 'A123', 1, '2023-10-28'),
(103, 'C789', 1, '2023-10-29');
```
</Callout>

#### 3NF (Third Normal Form): `Eliminate Redundant Data Dependent on Non-Key Attributes`

**Goal**: Remove data that is dependent on other non-key attributes. This is about eliminating transitive dependencies.

**Problem**: Let's say we have a `suppliers` table. We store supplier information, including their `zip_code`, `city`, and `state`. `supplier_id` is the primary key.

<Callout collapsed="">
```sql
CREATE TABLE [suppliers] (
    [supplier_id] VARCHAR(10) PRIMARY KEY,
    [supplier_name] VARCHAR(255),
    [zip_code] VARCHAR(10),
    [city] VARCHAR(100),
    [state] VARCHAR(50)
);

INSERT INTO [suppliers] ([supplier_id], [supplier_name], [zip_code], [city], [state]) VALUES
('S1', 'Acme Corp', '12345', 'Anytown', 'NY'),
('S2', 'Beta Inc', '67890', 'Otherville', 'CA'),
('S3', 'Gamma Ltd', '12345', 'Anytown', 'NY');
```
```
+---------------------------------------------------------------+
| suppliers                                                     |
+---------------------------------------------------------------+
| PK supplier_id | supplier_name | zip_code | city      | state |
+---------------------------------------------------------------+
| S1             | Acme Corp     | 12345    | Anytown    | NY   |
| S2             | Beta Inc      | 67890    | Otherville | CA   |
| S3             | Gamma Ltd     | 12345    | Anytown    | NY   |
+---------------------------------------------------------------+
```
</Callout>

**Solution**: To achieve 3NF, we remove the attributes dependent on the non-key attribute (`city`, `state` dependent on `zip_code`) and put 
them into a separate table keyed by the non-key attribute itself (`zip_code`).

<Callout collapsed="Normalization to 3NF: Visual explanation">
```
+-------------------+     1:M     +--------------------+
| zip_codes         | <---------- | suppliers          |
+-------------------+             +--------------------+
| PK zip_code       |             | PK supplier_id     |
| city              |             | supplier_name      |
| state             |             | FK zip_code        |
+-------------------+             +--------------------+
```
```sql
CREATE TABLE [zip_codes] (
    [zip_code] VARCHAR(10) PRIMARY KEY,
    [city] VARCHAR(100),
    [state] VARCHAR(50)
);

CREATE TABLE [suppliers] (
    [supplier_id] VARCHAR(10) PRIMARY KEY,
    [supplier_name] VARCHAR(255),
    [zip_code] VARCHAR(10), -- Foreign Key to zip_codes
    FOREIGN KEY ([zip_code]) REFERENCES [zip_codes]([zip_code])
);

-- Insert data into zip_codes
INSERT INTO [zip_codes] ([zip_code], [city], [state]) VALUES
('12345', 'Anytown', 'NY'),
('67890', 'Otherville', 'CA');

-- Insert data into suppliers (referencing zip_codes)
INSERT INTO [suppliers] ([supplier_id], [supplier_name], [zip_code]) VALUES
('S1', 'Acme Corp', '12345'),
('S2', 'Beta Inc', '67890'),
('S3', 'Gamma Ltd', '12345');
```
</Callout>

<Callout title="Good to know">
There are additional normal forms, such as `4NF`, `5NF`, `6NF`, `EKNF`, `ETNF`, and `DKNF`. We won't cover these here, but we will create a 
dedicated set of tutorials for them in our guides and tutorials section.
</Callout>

### Database Relationships
#### One-to-One

In a one-to-one relationship, each record in `table A` is related to at most one record in `table B`, and each record in `table B` is
related to at most one record in `table A`. It's a very direct, exclusive pairing.

<Callout collapsed="Use Cases & Examples">
1. **User Profiles and User Account Details**: Think of a website. Each user account (in a Users table) might have exactly one user profile (in a UserProfiles table) containing more detailed information.
2. **Employees and Parking Spaces**: An Employees table and a ParkingSpaces table. Each employee might be assigned at most one parking space, and each parking space is assigned to at most one employee.
3. **Splitting Tables for Organization**: Sometimes, you might split a very wide table into two for better organization or security reasons, maintaining a 1-1 relationship between them.

```
Table A (One Side)      Table B (One Side)
+---------+             +---------+
| PK (A)  | <---------> | FK (A)  | (Foreign Key referencing Table A)
| ...     |             | ...     |
+---------+             +---------+
```
</Callout>


#### One-to-Many

In a one-to-many relationship, one record in `table A` can be related to many records in `table B`, but each 
record in `table B` is related to at most one record in `table A`. Think of it as a "parent-child" relationship.

<Callout collapsed="Use Cases & Examples">
1. **Customers and Orders**: One customer can place many orders, but each order belongs to only one customer.
2. **Authors and Books**: One author can write many books, but (let's simplify for now and say) each book is written by one primary author.
3. **Departments and Employees**: One department can have many employees, but each employee belongs to only one department.

```
Table A (One Side)      Table B (Many Side)
+---------+             +---------+
| PK (A)  | ----------> | FK (A)  | (Foreign Key referencing Table A)
| ...     |             | ...     |
+---------+             +---------+
     (One)                  (Many)
```
</Callout>

#### Many-to-Many

In a many-to-many relationship, one record in `table A` can be related to many records in `table B`, and one 
record in `table B` can be related to many records in `table A`. It's a more complex, bidirectional relationship.

<Callout collapsed="Use Cases & Examples">
1. **Students and Courses**: One student can enroll in many courses, and one course can have many students enrolled.
2. **Products and Categories**: One product can belong to multiple categories (e.g., a "T-shirt" can be
in "Clothing" and "Summer Wear" categories), and one category can contain many products.
3. **Authors and Books**: A book can be written by multiple authors, and an author can write multiple books.

```
Table A (Many Side)    Junction Table      Table B (Many Side)
+---------+          +-------------+     +---------+
| PK (A)  | -------->| FK (A)      | <----| FK (B)  |
| ...     |          | FK (B)      |     | ...     |
+---------+          +-------------+     +---------+
     (Many)             (Junction)          (Many)
```
</Callout>

Many-to-many relationships are not directly implemented with foreign keys between the two main tables. 
Instead, you need a `junction` table (also called an associative table or bridging table). 
This table acts as an intermediary to link records from both tables.

```sql
-- Table for Students (Many side)
CREATE TABLE [students] (
    [id] INT PRIMARY KEY,
    [name] VARCHAR(255)
);

-- Table for Courses (Many side)
CREATE TABLE [courses] (
    [id] INT PRIMARY KEY,
    [name] VARCHAR(255),
    [credits] INT
);

-- Junction Table: Enrollments (Connects Students and Courses - M-M relationship)
CREATE TABLE [enrollments] (
    [id] INT IDENTITY(1,1) PRIMARY KEY, -- Optional, but good practice for junction tables
    [student_id] INT,
    [course_id] INT,
    [enrollment_date] DATE,
    -- Composite Foreign Keys (often part of a composite primary key or unique constraint)
    FOREIGN KEY ([student_id]) REFERENCES [students]([id]),
    FOREIGN KEY ([course_id]) REFERENCES [courses]([id]),
    UNIQUE ([student_id], [course_id]) -- Prevent duplicate enrollments for the same student and course
);
```

### Why Foreign Keys?

You might think of foreign key constraints as simply a way to validate data - ensuring 
that when you enter a value in a foreign key column, that value actually exists in the primary key 
column of another table. And you'd be partially right! This value checking is the mechanism foreign keys use.

But it's crucial to understand that this validation is not the end goal, it's the means 
to a much larger purpose. Foreign key constraints are fundamentally about:

<Callout collapsed="1. Explicitly Defining and Enforcing Relationships">

We've discussed relationships like `One-to-Many` between Customers and Orders. 
A foreign key is the SQL language's way of telling the database: 

> Hey database, I want to enforce a 1-M relationship here. Every value in the customer_id column of the
Orders table must correspond to a valid customer_id in the Customers table.

It's not just a suggestion; it's a constraint the database actively enforces. 
The database becomes relationship-aware because of the foreign key.
</Callout>

<Callout collapsed="2. Maintaining Referential Integrity">
- This is the core of "data integrity" in the context of relationships. Referential integrity means 
that relationships between tables remain consistent and valid over time.
- Foreign keys prevent orphaned records. What's an orphaned record? In our Customer-Order example, 
an order that exists in the Orders table but doesn't have a corresponding customer in the Customers 
table would be an orphan. Foreign keys prevent this from happening (or control what happens 
if you try to delete a customer with orders - via CASCADE, SET NULL, etc.).
- Why is preventing orphans important? Orphaned records break the logical structure of your data. 
If you have an order without a customer, you lose crucial context. Queries become unreliable, reports
 become inaccurate, and your application's logic can break down.

**Example**:
```
Without a foreign key, you could accidentally delete a customer from the Customers 
table while their orders still exist in the Orders table. Suddenly, you have orders that point to 
a customer that no longer exists! A foreign key constraint prevents this data inconsistency.
```
</Callout>

<Callout collapsed="3. Facilitating Database Design and Understanding">
- Foreign keys are not just about technical enforcement; they are also a crucial part of database design documentation.
- When you see a foreign key in a database schema, it immediately tells you: 
`Table 'X' is related to Table 'Y' in this way.` It's a clear visual and structural indicator of relationships.
- This makes databases easier to understand, maintain, and evolve over time. New developers can quickly 
grasp how different parts of the database are connected.
</Callout>

In essence, foreign key constraints are not just about checking values; they are about:

1. Defining the rules of your data relationships
2. Actively enforcing those rules at the database level
3. Guaranteeing data integrity and consistency within those relationships
4. Making your database more robust, reliable, and understandable

### Why NOT Foreign Keys?

While highly beneficial, there are some scenarios where you might reconsider or use Foreign Keys with caution. 
These are typically edge cases and often involve trade-offs.

<Callout collapsed="1. Performance Overhead in Very High-Write Environments">
- **Scenario**: Extremely high-volume transactional systems (e.g., real-time logging, very high-frequency trading
platforms, massive IoT data ingestion).
- **Explanation**: Every time you insert or update data in a table with a foreign key, the database system 
needs to perform checks to ensure referential integrity. In extremely high-write scenarios, these 
checks can introduce a small but potentially noticeable performance overhead.
</Callout>

<Callout collapsed="2. Distributed Database Systems and Cross-Node Foreign Keys:">
- **Scenario**: Systems where data is distributed across multiple database nodes or clusters (common in sharded databases, cloud environments, and microservices).
- **Explanation**:  Cross-node foreign keys can introduce significant complexity and performance overhead. Validating referential integrity requires communication between nodes, leading to increased latency. Distributed transactions needed to maintain consistency are also more complex and can be less performant than local transactions. In such architectures, application-level data integrity checks or eventual consistency models might be considered alternatives.
</Callout>

<Callout collapsed="3. Legacy Systems and Data Integration with Non-Relational Data:">
- **Scenario**: Integrating a relational database with older legacy systems or non-relational data stores (e.g., NoSQL, flat files, external APIs).
- **Explanation**:  Legacy systems or non-relational data might not consistently adhere to the referential integrity rules enforced by foreign keys.  Imposing foreign keys in such scenarios can lead to data import issues, data inconsistencies, and might necessitate complex data transformation or application-level integrity management instead. You might need to carefully evaluate the data quality and consistency of the external sources and potentially rely on application logic or ETL processes to ensure data integrity instead of strictly enforcing foreign keys at the database level.
</Callout>

You can also check out some great explanations from the PlanetScale team in their [article](https://planetscale.com/docs/learn/operating-without-foreign-key-constraints#why-does-planetscale-not-recommend-constraints)

### Polymorphic Relations

Polymorphic relationships are a more advanced concept that allows a single relationship to point to 
different types of entities or tables. It's about creating more flexible and adaptable relationships when 
you have different kinds of data that share some commonality.

Imagine you have an `activities` log. An activity could be a `comment` a `like` or a `share`.
Each of these `activity` types has different details. Instead of creating separate tables and 
relationships for each activity type and the things they relate to, you might use a polymorphic approach.

<Callout collapsed="Common Scenarios & Examples">
- **Comments/Reviews**: A "Comment" might be related to different types of content: articles, products, videos, etc. 
Instead of having separate article_id, product_id, video_id columns in a Comments table, you can use a 
polymorphic relationship.
```
+---------------------+
| **Comments**        |
+---------------------+
| PK comment_id       |
| commentable_type    | ------>  [Polymorphic Relationship]
| commentable_id      | -------->
| user_id             |
| comment_text        |
| ...                 |
+---------------------+
          ^
          |
+---------------------+    +---------------------+    +---------------------+
| **Articles**        |    | **Products**        |    | **Videos**          |
+---------------------+    +---------------------+    +---------------------+
| PK article_id       |    | PK product_id       |    | PK video_id         |
| ...                 |    | ...                 |    | ...                 |
+---------------------+    +---------------------+    +---------------------+
```
- **Notifications:** A notification could be related to a user, an order, a system event, etc.
```
+----------------------+
| **Notifications**    |
+----------------------+
| PK notification_id  |
| notifiable_type     | ------>  [Polymorphic Relationship]
| notifiable_id       | -------->
| user_id             |
| message             |
| ...                  |
+----------------------+
           ^
           |
+---------------------+    +---------------------+    +-----------------------+
| **Users**           |    | **Orders**          |    | **System Events**     |
+---------------------+    +---------------------+    +-----------------------+
| PK user_id          |    | PK order_id         |    | PK event_id           |
| ...                 |    | ...                 |    | ...                   |
+---------------------+    +---------------------+    +-----------------------+
```
</Callout>

Polymorphic relationships are more complex and are often handled at the application level or 
using more advanced database features (depending on the specific database system). Standard SQL doesn't 
have direct, built-in support for enforcing polymorphic foreign key constraints in the same way as regular foreign keys.

Source: https://orm.drizzle.team/docs/mssql/relations

import Tab from '@mdx/Tab.astro';
import Tabs from '@mdx/Tabs.astro';
import IsSupportedChipGroup from '@mdx/IsSupportedChipGroup.astro';
import Callout from '@mdx/Callout.astro';
import Section from '@mdx/Section.astro';

import CodeTab from '@mdx/CodeTab.astro';
import CodeTabs from '@mdx/CodeTabs.astro';

# Drizzle soft relations
The sole purpose of Drizzle relations is to let you query your relational data in the most simple and consise way:

<CodeTabs items={["Relational queries", "Select with joins"]}>
<Section>
```ts
import * as schema from './schema';
import { drizzle } from 'drizzle-orm/node-mssql';

const db = drizzle({ client, schema });

const result = db._query.users.findMany({
  with: {
    posts: true,
  },
});
```
```ts
[{
  id: 10,
  name: "Dan",
  posts: [
    {
      id: 1,
      content: "SQL is awesome",
      authorId: 10,
    },
    {
      id: 2,
      content: "But check relational queries",
      authorId: 10,
    }
  ]
}]
```
</Section>
<Section>
```ts
import { drizzle } from 'drizzle-orm/node-mssql';
import { eq } from 'drizzle-orm';
import { posts, users } from './schema';

const db = drizzle(client);

const res = await db.select()
                    .from(users)
                    .leftJoin(posts, eq(posts.authorId, users.id))
                    .orderBy(users.id)
const mappedResult =  
```
</Section>
</CodeTabs>


### One-to-one
Drizzle ORM provides you an API to define `one-to-one` relations between tables with the `relations` operator.

An example of a `one-to-one` relation between users and users, where a user can invite another (this example uses a self reference):

```typescript copy {10-15}
import { mssqlTable, ntext, int } from 'drizzle-orm/mssql-core';
import { relations } from 'drizzle-orm/_relations';

export const users = mssqlTable('users', {
	id: int().identity().primaryKey(),
	name: ntext(),
	invitedBy: int('invited_by'),
});

export const usersRelations = relations(users, ({ one }) => ({
	invitee: one(users, {
		fields: [users.invitedBy],
		references: [users.id],
	}),
}));
```

Another example would be a user having a profile information stored in separate table. In this case, because the foreign key is stored in the "profile_info" table, the user relation have neither fields or references. This tells Typescript that `user.profileInfo` is nullable:

```typescript copy {9-17}
import { mssqlTable, ntext, int } from 'drizzle-orm/mssql-core';
import { relations } from 'drizzle-orm/_relations';

export const users = mssqlTable('users', {
	id: int().identity().primaryKey(),
	name: ntext(),
});

export const usersRelations = relations(users, ({ one }) => ({
	profileInfo: one(profileInfo),
}));

export const profileInfo = mssqlTable('profile_info', {
	id: int().identity().primaryKey(),
	userId: int('user_id').references(() => users.id),
	metadata: ntext(),
});

export const profileInfoRelations = relations(profileInfo, ({ one }) => ({
	user: one(users, { fields: [profileInfo.userId], references: [users.id] }),
}));

const user = await queryUserWithProfileInfo();
//____^? type { id: number, profileInfo: string | null  }
```

### One-to-many
Drizzle ORM provides you an API to define `one-to-many` relations between tables with `relations` operator. 

Example of `one-to-many` relation between users and posts they've written:

```typescript copy {9-11, 19-24}
import { mssqlTable, ntext, int } from 'drizzle-orm/mssql-core';
import { relations } from 'drizzle-orm/_relations';

export const users = mssqlTable('users', {
	id: int().identity().primaryKey(),
	name: ntext(),
});

export const usersRelations = relations(users, ({ many }) => ({
	posts: many(posts),
}));

export const posts = mssqlTable('posts', {
	id: int().identity().primaryKey(),
	content: ntext(),
	authorId: int('author_id'),
});

export const postsRelations = relations(posts, ({ one }) => ({
	author: one(users, {
		fields: [posts.authorId],
		references: [users.id],
	}),
}));
```

Now lets add comments to the posts:
```typescript copy {14,17-22,24-29}
...

export const posts = mssqlTable('posts', {
	id: int().identity().primaryKey(),
	content: ntext(),
	authorId: int('author_id'),
});

export const postsRelations = relations(posts, ({ one, many }) => ({
	author: one(users, {
		fields: [posts.authorId],
		references: [users.id],
	}),
	comments: many(comments)
}));

export const comments = mssqlTable('comments', {
	id: int().identity().primaryKey(),
	text: ntext(),
	authorId: int('author_id'),
	postId: int('post_id'),
});

export const commentsRelations = relations(comments, ({ one }) => ({
	post: one(posts, {
		fields: [comments.postId],
		references: [posts.id],
	}),
}));
```


### Many-to-many
Drizzle ORM provides you an API to define `many-to-many` relations between tables through so called `junction` or `join` tables,
they have to be explicitly defined and store associations between related tables.  
  
Example of `many-to-many` relation between users and groups:
```typescript copy {9-11, 18-20, 37-46}
import { relations } from 'drizzle-orm/_relations';
import { int, mssqlTable, primaryKey, ntext } from 'drizzle-orm/mssql-core';

export const users = mssqlTable('users', {
  id: int().identity().primaryKey(),
  name: ntext(),
});

export const usersRelations = relations(users, ({ many }) => ({
  usersToGroups: many(usersToGroups),
}));

export const groups = mssqlTable('groups', {
  id: int().identity().primaryKey(),
  name: ntext(),
});

export const groupsRelations = relations(groups, ({ many }) => ({
  usersToGroups: many(usersToGroups),
}));

export const usersToGroups = mssqlTable(
  'users_to_groups',
  {
    userId: int('user_id')
      .notNull()
      .references(() => users.id),
    groupId: int('group_id')
      .notNull()
      .references(() => groups.id),
  },
  (t) => [
		primaryKey({ columns: [t.userId, t.groupId] })
	],
);

export const usersToGroupsRelations = relations(usersToGroups, ({ one }) => ({
  group: one(groups, {
    fields: [usersToGroups.groupId],
    references: [groups.id],
  }),
  user: one(users, {
    fields: [usersToGroups.userId],
    references: [users.id],
  }),
}));
```

### Foreign keys

You might've noticed that `relations` look similar to foreign keys — they even have a `references` property. So what's the difference?

While foreign keys serve a similar purpose, defining relations between tables, they work on a different level compared to `relations`.

Foreign keys are a database level constraint, they are checked on every `insert`/`update`/`delete` operation and throw an error if a constraint is violated.
On the other hand, `relations` are a higher level abstraction, they are used to define relations between tables on the application level only.
They do not affect the database schema in any way and do not create foreign keys implicitly.

What this means is `relations` and foreign keys can be used together, but they are not dependent on each other.
You can define `relations` without using foreign keys (and vice versa), which allows them to be used with databases that do not support foreign keys.

The following two examples will work exactly the same in terms of querying the data using Drizzle relational queries.
<CodeTabs items={["schema1.ts", "schema2.ts"]}>
<CodeTab>
```ts {15}
export const users = mssqlTable('users', {
  id: int().identity().primaryKey(),
  name: ntext(),
});

export const profileInfo = mssqlTable('profile_info', {
  id: int().identity().primaryKey(),
  userId: int('user_id'),
  metadata: nvarchar({ mode: 'json' }),
});

export const profileInfoRelations = relations(profileInfo, ({ one }) => ({
  user: one(users, {
    fields: [profileInfo.userId],
    references: [users.id],
  }),
}));
```
</CodeTab>
<CodeTab>
```ts {15}
export const users = mssqlTable('users', {
  id: int().identity().primaryKey(),
  name: ntext(),
});

export const profileInfoRelations = relations(profileInfo, ({ one }) => ({
  user: one(users, {
    fields: [profileInfo.userId],
    references: [users.id],
  }),
}));

export const profileInfo = mssqlTable('profile_info', {
  id: int().identity().primaryKey(),
  userId: int('user_id').references(() => users.id),
  metadata: nvarchar({ mode: 'json' }),
});
```
</CodeTab>
</CodeTabs>

### Foreign key actions

For more information check the [MSSQL foreign keys docs](https://learn.microsoft.com/en-us/sql/relational-databases/tables/create-foreign-key-relationships?view=sql-server-ver17)

You can specify actions that should occur when the referenced data in the parent table is modified. These actions are known as "foreign key actions." MSSQL provides several options for these actions.

On Delete/ Update Actions

- `CASCADE`: When a row in the parent table is deleted, all corresponding rows in the child table will also be deleted. This ensures that no orphaned rows exist in the child table.

- `NO ACTION`: This is the default action. It prevents the deletion of a row in the parent table if there are related rows in the child table. The DELETE operation in the parent table will fail.

- `SET DEFAULT`: If a row in the parent table is deleted, the foreign key column in the child table will be set to its default value if it has one. If it doesn't have a default value, the DELETE operation will fail.

- `SET NULL`: When a row in the parent table is deleted, the foreign key column in the child table will be set to NULL. This action assumes that the foreign key column in the child table allows NULL values.

> Analogous to ON DELETE there is also ON UPDATE which is invoked when a referenced column is changed (updated). The possible actions are the same, except that column lists cannot be specified for SET NULL and SET DEFAULT. In this case, CASCADE means that the updated values of the referenced column(s) should be copied into the referencing row(s).
in drizzle you can add foreign key action using `references()` second argument.

type of the actions

```typescript
export type UpdateDeleteAction = 'cascade' | 'no action' | 'set null' | 'set default';

// second argument of references interface
actions?: {
		onUpdate?: UpdateDeleteAction;
		onDelete?: UpdateDeleteAction;
	} | undefined
```

In the following example, adding `onDelete: 'cascade'` to the author field on the `posts` schema means that deleting the `user` will also delete all related Post records.


```typescript {11}
import { mssqlTable, ntext, int } from 'drizzle-orm/mssql-core';

export const users = mssqlTable('users', {
	id: int().identity().primaryKey(),
	name: ntext(),
});

export const posts = mssqlTable('posts', {
	id: int().identity().primaryKey(),
	name: ntext(),
	author: int().references(() => users.id, {onDelete: 'cascade'}).notNull(),
});
```

For constraints specified with the `foreignKey` operator, foreign key actions are defined with the syntax:

```typescript {18-19}
import { foreignKey, mssqlTable, ntext, int } from 'drizzle-orm/mssql-core';

export const users = mssqlTable('users', {
	id: int().identity().primaryKey(),
	name: ntext(),
});

export const posts = mssqlTable('posts', {
	id: int().identity().primaryKey(),
	name: ntext(),
	author: int().notNull(),
}, (table) => [
	foreignKey({
		name: "author_fk",
		columns: [table.author],
		foreignColumns: [users.id],
	})
		.onDelete('cascade')
		.onUpdate('cascade')
]);
```

### Disambiguating relations

Drizzle also provides the `relationName` option as a way to disambiguate
relations when you define multiple of them between the same two tables. For
example, if you define a `posts` table that has the `author` and `reviewer`
relations.

```ts {9-12, 21-32}
import { mssqlTable, ntext, int } from 'drizzle-orm/mssql-core';
import { relations } from 'drizzle-orm/_relations';
 
export const users = mssqlTable('users', {
	id: int().identity().primaryKey(),
	name: ntext(),
});
 
export const usersRelations = relations(users, ({ many }) => ({
	author: many(posts, { relationName: 'author' }),
	reviewer: many(posts, { relationName: 'reviewer' }),
}));
 
export const posts = mssqlTable('posts', {
	id: int().identity().primaryKey(),
	content: ntext(),
	authorId: int('author_id'),
	reviewerId: int('reviewer_id'),
});
 
export const postsRelations = relations(posts, ({ one }) => ({
	author: one(users, {
		fields: [posts.authorId],
		references: [users.id],
		relationName: 'author',
	}),
	reviewer: one(users, {
		fields: [posts.reviewerId],
		references: [users.id],
		relationName: 'reviewer',
	}),
}));
```


Source: https://orm.drizzle.team/docs/mssql/rqb

import Callout from '@mdx/Callout.astro';
import CodeTabs from '@mdx/CodeTabs.astro';
import CodeTab from '@mdx/CodeTab.astro';
import Section from '@mdx/Section.astro';

# Drizzle Queries

Drizzle ORM is designed to be a thin typed layer on top of SQL. 
We truly believe we've designed the best way to operate an SQL database from TypeScript and it's time to make it better.  
  
Relational queries are meant to provide you with a great developer experience for querying 
nested relational data from an SQL database, avoiding multiple joins and complex data mappings.  

It is an extension to the existing schema definition and query builder. 
You can opt-in to use it based on your needs. 
We've made sure you have both the best-in-class developer experience and performance.  

<CodeTabs items={["index.ts", "schema.ts"]}>
	<CodeTab>
	```typescript copy /schema/3
	import * as schema from './schema';
	import { drizzle } from 'drizzle-orm/node-mssql';

	const db = drizzle({ schema });

	const result = await db._query.users.findMany({
		with: {
			posts: true			
		},
	});
	```

	```ts
	[{
		id: 10,
		name: "Dan",
		posts: [
			{
				id: 1,
				content: "SQL is awesome",
				authorId: 10,
			},
			{
				id: 2,
				content: "But check relational queries",
				authorId: 10,
			}
		]
	}]
	```
	</CodeTab>

	```typescript copy
	import { int, mssqlTable, text } from 'drizzle-orm/mssql-core';
	import { relations } from 'drizzle-orm/_relations';

	export const users = mssqlTable('users', {
		id: int().primaryKey().identity(),
		name: text().notNull(),
	});

	export const usersRelations = relations(users, ({ many }) => ({
		posts: many(posts),
	}));

	export const posts = mssqlTable('posts', {
		id: int().primaryKey().identity(),
		content: text().notNull(),
		authorId: int('author_id').notNull(),
	});

	export const postsRelations = relations(posts, ({ one }) => ({
		author: one(users, { fields: [posts.authorId], references: [users.id] }),
	}));
	```
</CodeTabs>

⚠️ If you have SQL schema declared in multiple files you can do it like that
<CodeTabs items={["index.ts", "schema1.ts", "schema2.ts"]}>
	```typescript copy /schema/3
	import * as schema1 from './schema1';
	import * as schema2 from './schema2';
	import { drizzle } from 'drizzle-orm/node-mssql';

	const db = drizzle({ schema: { ...schema1, ...schema2 } });

	const result = await db._query.users.findMany({
		with: {
			posts: true			
		},
	});
	```
	
	```ts
	// schema declaration in the first file
	```
	```ts
	// schema declaration in the second file
	```
</CodeTabs>

## Querying
Relational queries are an extension to Drizzle's original **[query builder](/docs/mssql/select)**.
You need to provide all `tables` and `relations` from your schema file/files upon `drizzle()` 
initialization and then just use the `db._query` API.
<Callout type="info" emoji="ℹ️">
	`drizzle` import path depends on the **[database driver](/docs/mssql/connect-overview)** you're using.
</Callout>
<CodeTabs items={["index.ts", "schema.ts"]}>
<CodeTab>
```ts
import * as schema from './schema';
import { drizzle } from 'drizzle-orm/node-mssql';

const db = drizzle({ schema });

await db._query.users.findMany(...);
```
```ts
// if you have schema in multiple files
import * as schema1 from './schema1';
import * as schema2 from './schema2';
import { drizzle } from 'drizzle-orm/node-mssql';

const db = drizzle({ schema: { ...schema1, ...schema2 } });

await db._query.users.findMany(...);
```
</CodeTab>
```typescript copy
	import { type AnyMsSqlColumn, bit, int, mssqlTable, primaryKey, text, datetime2 } from 'drizzle-orm/mssql-core';

	import { relations } from 'drizzle-orm/_relations';

	export const users = mssqlTable('users', {
		id: int('id').primaryKey().identity(),
		name: text('name').notNull(),
		verified: bit('verified').notNull(),
		invitedBy: int('invited_by').references((): AnyMsSqlColumn => users.id),
	});

	export const usersRelations = relations(users, ({ one, many }) => ({
		invitee: one(users, { fields: [users.invitedBy], references: [users.id] }),
		usersToGroups: many(usersToGroups),
		posts: many(posts),
	}));

	export const groups = mssqlTable('groups', {
		id: int('id').primaryKey().identity(),
		name: text('name').notNull(),
		description: text('description'),
	});

	export const groupsRelations = relations(groups, ({ many }) => ({
		usersToGroups: many(usersToGroups),
	}));

	export const usersToGroups = mssqlTable('users_to_groups', {
		id: int('id').primaryKey().identity(),
		userId: int('user_id').notNull().references(() => users.id),
		groupId: int('group_id').notNull().references(() => groups.id),
	}, (t) => [
		primaryKey({ columns: [t.userId, t.groupId] })
	]);

	export const usersToGroupsRelations = relations(usersToGroups, ({ one }) => ({
		group: one(groups, { fields: [usersToGroups.groupId], references: [groups.id] }),
		user: one(users, { fields: [usersToGroups.userId], references: [users.id] }),
	}));

	export const posts = mssqlTable('posts', {
		id: int('id').primaryKey().identity(),
		content: text('content').notNull(),
		authorId: int('author_id').references(() => users.id),
		createdAt: datetime2('created_at').notNull().defaultGetDate(),
	});

	export const postsRelations = relations(posts, ({ one, many }) => ({
		author: one(users, { fields: [posts.authorId], references: [users.id] }),
		comments: many(comments),
	}));

	export const comments = mssqlTable('comments', {
		id: int('id').primaryKey().identity(),
		content: text('content').notNull(),
		creator: int('creator').references(() => users.id),
		postId: int('post_id').references(() => posts.id),
		createdAt: datetime2('created_at').notNull().defaultGetDate(),
	});

	export const commentsRelations = relations(comments, ({ one, many }) => ({
		post: one(posts, { fields: [comments.postId], references: [posts.id] }),
		author: one(users, { fields: [comments.creator], references: [users.id] }),
		likes: many(commentLikes),
	}));

	export const commentLikes = mssqlTable('comment_likes', {
		id: int('id').primaryKey().identity(),
		creator: int('creator').references(() => users.id),
		commentId: int('comment_id').references(() => comments.id),
		createdAt: datetime2('created_at').notNull().defaultGetDate(),
	});

	export const commentLikesRelations = relations(commentLikes, ({ one }) => ({
		comment: one(comments, { fields: [commentLikes.commentId], references: [comments.id] }),
		author: one(users, { fields: [commentLikes.creator], references: [users.id] }),
	}));
```
</CodeTabs>

Drizzle provides `.findMany()` and `.findFirst()` APIs.
### Find many
<Section>
```typescript copy
const users = await db._query.users.findMany();
```
```ts
// result type
const result: {
	id: number;
	name: string;
	verified: bit;
	invitedBy: number | null;
}[];
```
</Section>

### Find first
<Callout>
  `.findFirst()` will add `limit 1` to the query.
</Callout>
<Section>
```typescript copy
const user = await db._query.users.findFirst();
```
```ts
// result type
const result: {
	id: number;
	name: string;
	verified: bit;
	invitedBy: number | null;
};
```
</Section>

### Include relations

`With` operator lets you combine data from multiple related tables and properly aggregate results.

**Getting all posts with comments:**
```typescript copy
const posts = await db._query.posts.findMany({
	with: {
		comments: true,
	},
});
```

**Getting first post with comments:**
```typescript copy
const post = await db._query.posts.findFirst({
	with: {
		comments: true,
	},
});
```

You can chain nested with statements as much as necessary.  
For any nested `with` queries Drizzle will infer types using [Core Type API](/docs/mssql/goodies#type-api).
  
**Get all users with posts. Each post should contain a list of comments:**
```typescript copy
const users = await db._query.users.findMany({
	with: {
		posts: {
			with: {
				comments: true,
			},
		},
	},
});
```

### Partial fields select
`columns` parameter lets you include or omit columns you want to get from the database.

<Callout type="info" emoji="ℹ️">
  Drizzle performs partial selects on the query level, no additional data is transferred from the database.

  Keep in mind that **a single SQL statement is outputted by Drizzle.**
</Callout>

**Get all posts with just `id`, `content` and include `comments`:**
```typescript copy
const posts = await db._query.posts.findMany({
	columns: {
		id: true,
		content: true,
	},
	with: {
		comments: true,
	}
});
```

**Get all posts without `content`:**
```typescript copy
const posts = await db._query.posts.findMany({
	columns: {
		content: false,
	},
});
```

<Callout type="info" emoji="ℹ️">
When both `true` and `false` select options are present, all `false` options are ignored.
</Callout>

If you include the `name` field and exclude the `id` field, `id` exclusion will be redundant, 
all fields apart from `name` would be excluded anyways.  
  
**Exclude and Include fields in the same query:**
<Section>
```typescript copy
const users = await db._query.users.findMany({
	columns: {
		name: true,
		id: false //ignored
	},
});
```
```ts
// result type
const users: {
	name: string;
};
```
</Section>

**Only include columns from nested relations:**
<Section>
```typescript copy
const res = await db._query.users.findMany({
	columns: {},
	with: {
		posts: true
	}
});
```
```ts
// result type
const res: {
	posts: {
		id: number,
		text: string
	}
}[];
```
</Section>

### Nested partial fields select
Just like with **[`partial select`](#partial-select)**, you can include or exclude columns of nested relations:
```typescript copy
const posts = await db._query.posts.findMany({
	columns: {
		id: true,
		content: true,
	},
	with: {
		comments: {
			columns: {
				authorId: false
			}
		}
	}
});
```

### Select filters
Just like in our SQL-like query builder, 
relational queries API lets you define filters and conditions with the list of our **[`operators`](/docs/mssql/operators)**.  

You can either import them from `drizzle-orm` or use from the callback syntax:
<Section>
```typescript copy
import { eq } from 'drizzle-orm';

const users = await db._query.users.findMany({
	where: eq(users.id, 1)
})
```
```ts copy
const users = await db._query.users.findMany({
	where: (users, { eq }) => eq(users.id, 1),
})
```
</Section>

Find post with `id=1` and comments that were created before particular date:
```typescript copy
await db._query.posts.findMany({
	where: (posts, { eq }) => (eq(posts.id, 1)),
	with: {
		comments: {
			where: (comments, { lt }) => lt(comments.createdAt, new Date()),
		},
	},
});
```

### Limit & Offset
Drizzle ORM provides `limit` & `offset` API for queries and for the nested entities.
  
**Find 5 posts:**
```typescript copy
await db._query.posts.findMany({
	limit: 5,
});
```

**Find posts and get 3 comments at most:**
```typescript copy
await db._query.posts.findMany({
	with: {
		comments: {
			limit: 3,
		},
	},
});
```

<Callout type="warning" emoji="⚠️">
  `offset` is only available for top level query.
</Callout>
```typescript 
await db._query.posts.findMany({
	limit: 5,
	offset: 2, // correct ✅
	with: {
		comments: {
			offset: 3, // incorrect ❌
			limit: 3,
		},
	},
});
```

Find posts with comments from the 6th to the 10th post:
```typescript copy
await db._query.posts.findMany({
	limit: 5,
	offset: 5,
	with: {
		comments: true,
	},
});
```

### Order By
Drizzle provides API for ordering in the relational query builder.  

You can use same ordering **[core API](/docs/mssql/select#order-by)** or use
`order by` operator from the callback with no imports.  

<Section>
```typescript copy
import { desc, asc } from 'drizzle-orm';

await db._query.posts.findMany({
	orderBy: [asc(posts.id)],
});
```
```typescript copy
await db._query.posts.findMany({
	orderBy: (posts, { asc }) => [asc(posts.id)],
});
```
</Section>

**Order by `asc` + `desc`:**
```typescript copy
await db._query.posts.findMany({
	orderBy: (posts, { asc }) => [asc(posts.id)],
	with: {
		comments: {
			orderBy: (comments, { desc }) => [desc(comments.id)],
		},
	},
});
```

### Include custom fields
Relational query API lets you add custom additional fields. 
It's useful when you need to retrieve data and apply additional functions to it.
<Callout type="warning" emoji="⚠️">
	As of now aggregations are not supported in `extras`, please use **[`core queries`](/docs/mssql/select)** for that.
</Callout>

<Section>
```typescript copy {5}
import { sql } from 'drizzle-orm';

await db._query.users.findMany({
	extras: {
		loweredName: sql`lower(${users.name})`.as('lowered_name'),
	},
})
```
```typescript copy {3}
await db._query.users.findMany({
  extras: (table, { sql }) => ({
    loweredName: sql`lower(${table.name})`.as('lowered_name'),
  }),
})
```

</Section>

`lowerName` as a key will be included to all fields in returned object.

<Callout type="warning" emoji="⚠️">
  You have to explicitly specify `.as("<name_for_column>")`
</Callout>

To retrieve all users with groups, but with the fullName field included (which is a concatenation of firstName and lastName), 
you can use the following query with the Drizzle relational query builder.

<Section>
```typescript copy
const res = await db._query.users.findMany({
	extras: {
		fullName: sql<string>`concat(${users.name}, " ", ${users.name})`.as('full_name'),
	},
	with: {
		usersToGroups: {
			columns: {},
			with: {
				group: true,
			},
		},
	},
});
```
```ts
// result type
const res: {
    id: number;
    name: string;
    verified: boolean;
    invitedBy: number | null;
    fullName: string;
    usersToGroups: {
        group: {
            id: number;
            name: string;
            description: string | null;
        };
    }[];
}[];

```
</Section>

To retrieve all posts with comments and add an additional field to calculate the size of the post content and the size of each comment content:
<Section>
```typescript copy
const res = await db._query.posts.findMany({
	extras: (table, { sql }) => ({
		contentLength: (sql<number>`length(${table.content})`).as('content_length'),
	}),
	with: {
		comments: {
			extras: {
				commentSize: sql<number>`length(${comments.content})`.as('comment_size'),
			},
		},
	},
});
```
```ts
// result type
const res: {
    id: number;
    createdAt: Date;
    content: string;
    authorId: number | null;
    contentLength: number;
    comments: {
        id: number;
        createdAt: Date;
        content: string;
        creator: number | null;
        postId: number | null;
        commentSize: number;
    }[];
}[];
```
</Section>

### Prepared statements
Prepared statements are designed to massively improve query performance — [see here.](/docs/mssql/perf-queries)

In this section, you can learn how to define placeholders and execute prepared statements 
using the Drizzle relational query builder.

##### **Placeholder in `where`**

<Section>
```ts copy
const prepared = db._query.users.findMany({
	where: ((users, { eq }) => eq(users.id, sql.placeholder('id'))),
	with: {
		posts: {
			where: ((posts, { eq }) => eq(posts.id, sql.placeholder('pid'))),
		},
	},
}).prepare();

const usersWithPosts = await prepared.execute({ id: 1, pid: 1 });
```
</Section>

##### **Placeholder in `limit`**

<Section>
```ts copy
const prepared = db._query.users.findMany({
	with: {
		posts: {
			limit: placeholder('limit'),
		},
	},
}).prepare();

const usersWithPosts = await prepared.execute({ limit: 1 });
```
</Section>

##### **Placeholder in `offset`**

<Section>
```ts copy
const prepared = db._query.users.findMany({
	offset: placeholder('offset'),
	with: {
		posts: true,
	},
}).prepare();

const usersWithPosts = await prepared.execute({ offset: 1 });
```
</Section>

##### **Multiple placeholders**

<Section>
```ts copy
const prepared = db._query.users.findMany({
	limit: placeholder('uLimit'),
	offset: placeholder('uOffset'),
	where: ((users, { eq, or }) => or(eq(users.id, placeholder('id')), eq(users.id, 3))),
	with: {
		posts: {
			where: ((users, { eq }) => eq(users.id, placeholder('pid'))),
			limit: placeholder('pLimit'),
		},
	},
}).prepare();

const usersWithPosts = await prepared.execute({ pLimit: 1, uLimit: 3, uOffset: 1, id: 2, pid: 6 });
```
</Section>


Source: https://orm.drizzle.team/docs/mssql/schemas

import Section from '@mdx/Section.astro';
import Callout from '@mdx/Callout.astro';

# Table schemas

If you declare an entity within a schema, query builder will prepend schema names in queries:<br/>
`select * from [schema].[users]`

<Section>
    ```ts copy {3,5}
    import { int, text, mssqlSchema, nvarchar } from 'drizzle-orm/mssql-core';

    export const mySchema = mssqlSchema('my_schema');

    export const mySchemaUsers = mySchema.table('users', {
      id: int().identity().primaryKey(),
      name: text(),
      color: nvarchar({ length: 100 }).default('red'),
    });
    ```
    ```sql
    CREATE SCHEMA [my_schema];
    
    CREATE TABLE [my_schema].[users] (
      [id] int IDENTITY(1, 1),
      [name] text,
      [color] nvarchar(100) CONSTRAINT [users_color_default] DEFAULT ('red'),
      CONSTRAINT [users_pkey] PRIMARY KEY([id])
    );
    ```
    </Section>

Source: https://orm.drizzle.team/docs/mssql/seed-functions

import Callout from '@mdx/Callout.astro';
import Tab from "@mdx/Tab.astro";
import Tabs from "@mdx/Tabs.astro";

# Generators

<Callout title='warning'>
For now, specifying `arraySize` along with `isUnique` in generators that support it will result in unique values being generated (not unique arrays), which will then be packed into arrays.
</Callout>

## ---

### `default`

<rem025 />
Generates the same given value each time the generator is called.

|  | param          | default     | type
|:-| :--------      | :--------   | :--------
|  |`defaultValue`  |--           |`any`
|  |`arraySize`     |--           |`number`

<rem025 />

```ts 
import { seed } from "drizzle-seed";

await seed(db, schema, { count: 1000 }).refine((funcs) => ({
  posts: {
    columns: {
      content: funcs.default({
        // value you want to generate
        defaultValue: "post content",

        // number of elements in each one-dimensional array. 
        // (If specified, arrays will be generated.)
        arraySize: 3
      }),
    },
  },
}));

```

### `valuesFromArray`

<rem025 />
Generates values from given array

|  | param      | default                     | type
|:-| :--------  | :--------                   | :--------
|  |`values`    |--                           |`any[]` \| `{ weight: number; values: any[] }[]`
|  |`isUnique`  |`database column uniqueness` |`bit`
|  |`arraySize` |--                           |`number`


<rem025 />
```ts 
import { seed } from "drizzle-seed";

await seed(db, schema, { count: 1000 }).refine((funcs) => ({
  posts: {
    columns: {
      title: funcs.valuesFromArray({
        // Array of values you want to generate (can be an array of weighted values)
        values: ["Title1", "Title2", "Title3", "Title4", "Title5"],

        // Property that controls whether the generated values will be unique or not
        isUnique: true,
        
        // number of elements in each one-dimensional array. 
        // (If specified, arrays will be generated.)
        arraySize: 3
      }),
    },
  },
}));

```

### `intPrimaryKey`

<rem025 />
Generates sequential integers starting from 1.

|  | param      | default    | type
|:-| :--------  | :--------  | :--------
|  |--          |--          |--

<rem025 />

```ts 
import { seed } from "drizzle-seed";

await seed(db, schema, { count: 1000 }).refine((funcs) => ({
  posts: {
    columns: {
      id: funcs.intPrimaryKey(),
    },
  },
}));

```

### `number`

<rem025 />
Generates numbers with a floating point within the given range

|  | param      | default                                                                                               | type
|:-| :--------  | :--------                                                                                             | :--------
|  |`isUnique`  |`database column uniqueness`                                                                           |`bit`
|  |`precision` |`100`                                                                                                  |`number`
|  |`maxValue`  |``` `precision * 1000` if isUnique equals false``` ``` `precision * count` if isUnique equals true```  |`number`
|  |`minValue`  |`-maxValue`                                                                                            |`number`
|  |`arraySize` |--                                                                                                     |`number`

<rem025 />
```ts 
import { seed } from "drizzle-seed";

await seed(db, schema, { count: 1000 }).refine((funcs) => ({
  products: {
    columns: {
      unitPrice: funcs.number({
        // lower border of range.
        minValue: 10,

        // upper border of range.
        maxValue: 120,
        
        // precision of generated number:
        // precision equals 10 means that values will be accurate to one tenth (1.2, 34.6);
        // precision equals 100 means that values will be accurate to one hundredth (1.23, 34.67).
        precision: 100,

        // property that controls if generated values gonna be unique or not.
        isUnique: false,

        // number of elements in each one-dimensional array. 
        // (If specified, arrays will be generated.)
        arraySize: 3
      }),
    },
  },
}));

```

### `int`

<rem025 />
Generates integers within the given range

|  | param      | default                                                                            | type
|:-| :--------  | :--------                                                                          | :--------
|  |`isUnique`  |`database column uniqueness`                                                        |`bit`
|  |`maxValue`  |``` `1000` if isUnique equals false``` ``` `count * 10` if isUnique equals true```  |`number \| bigint`
|  |`minValue`  |`-maxValue`                                                                         |`number \| bigint`
|  |`arraySize` |--                                                                                  |`number`

<rem025 />
```ts 
import { seed } from "drizzle-seed";

await seed(db, schema, { count: 1000 }).refine((funcs) => ({
  products: {
    columns: {
      unitsInStock: funcs.int({
        // lower border of range.
        minValue: 0,

        // lower border of range.
        maxValue: 100,

        // property that controls if generated values gonna be unique or not.
        isUnique: false,

        // number of elements in each one-dimensional array. 
        // (If specified, arrays will be generated.)
        arraySize: 3
      }),
    },
  },
}));

```

### `bit`

<rem025 />
Generates bit values (true or false)

|  | param      | default    | type
|:-| :--------  | :--------  | :--------
|  |`arraySize` |--          |`number`

<rem025 />
```ts 
import { seed } from "drizzle-seed";

await seed(db, schema, { count: 1000 }).refine((funcs) => ({
  users: {
    columns: {
      isAvailable: funcs.bit({
        // number of elements in each one-dimensional array. 
        // (If specified, arrays will be generated.)
        arraySize: 3
      }),
    },
  },
}));

```

### `date`

<rem025 />
Generates a date within the given range

|  | param      | default                                                                                                   | type
|:-| :--------  | :--------------                                                                                           | :--------
|  |`minDate`   |``` `'2024-05-08' - 4 years` - if maxDate is not set``` ``` `maxDate - 8 years`  - if maxDate is set ```   |`string \| Date`
|  |`maxDate`   |``` `'2024-05-08' + 4 years` - if minDate is not set``` ``` `minDate + 8 years`  - if minDate is set ```   |`string \| Date`
|  |`arraySize` |--                                                                                                         |`number`

<Callout type='warning'>
If only one of the parameters (`minDate` or `maxDate`) is provided, the unspecified parameter will be calculated by adding or subtracting 8 years to/from the specified one
</Callout>

<rem025 />
```ts 
import { seed } from "drizzle-seed";

await seed(db, schema, { count: 1000 }).refine((funcs) => ({
  users: {
    columns: {
      birthDate: funcs.date({
        // lower border of range.
        minDate: "1990-01-01",

        // upper border of range.
        maxDate: "2010-12-31",

        // number of elements in each one-dimensional array. 
        // (If specified, arrays will be generated.)
        arraySize: 3
      }),
    },
  },
}));

```

### `time`

<rem025 />
Generates time in 24-hour format

|  | param      | default             | type
|:-| :--------  | :--------           | :--------
|  |`min`       |`'00:00:00.000Z'`    |`string \| Date`
|  |`max`       |`'23:59:59.999Z'`    |`string \| Date`
|  |`arraySize` |--                   |`number`

<rem025 />
```ts 
import { seed } from "drizzle-seed";

await seed(db, schema, { count: 1000 }).refine((funcs) => ({
  users: {
    columns: {
      birthTime: funcs.time({
        // lower border of range.
        min: "11:12:13.141",

        // upper border of range.
        max: "15:16:17.181",

        // number of elements in each one-dimensional array. 
        // (If specified, arrays will be generated.)
        arraySize: 3
      }),
    },
  },
}));

```

### `timestamp`

<rem025 />
Generates timestamps

|  | param           | default                                                                                       | type
|:-| :--------       | :--------                                                                                     | :--------
|  |`min`            |``` `'2024-05-08' - 2 years` - if max is not set``` ``` `max - 4 years`  - if max is set ```   |`string \| Date`
|  |`max`            |``` `'2024-05-08' + 2 years` - if min is not set``` ``` `min + 4 years`  - if min is set ```   |`string \| Date`
|  |`arraySize`      |--                                                                                             |`number`

<rem025 />
```ts 
import { seed } from "drizzle-seed";

await seed(db, schema, { count: 1000 }).refine((funcs) => ({
  orders: {
    columns: {
      shippedDate: funcs.timestamp({
        // lower border of range.
        min: "2025-03-07T11:12:13.141",

        // upper border of range.
        max: "2025-03-08T15:16:17.181",

        // number of elements in each one-dimensional array. 
        // (If specified, arrays will be generated.)
        arraySize: 3
      }),
    },
  },
}));

```

### `datetime`

<rem025 />
Generates datetime objects

|  | param        | default                                                                                       | type
|:-| :--------    | :--------                                                                                     | :--------
|  |`min`         |``` `'2024-05-08' - 2 years` - if max is not set``` ``` `max - 4 years`  - if max is set ```   |`string \| Date`
|  |`max`         |``` `'2024-05-08' + 2 years` - if min is not set``` ``` `min + 4 years`  - if min is set ```   |`string \| Date`
|  |`arraySize`   |--                                                                                             |`number`
<rem025 />
```ts 
import { seed } from "drizzle-seed";

await seed(db, schema, { count: 1000 }).refine((funcs) => ({
  orders: {
    columns: {
      shippedDate: funcs.datetime({
        // lower border of range.
        min: "2025-03-07 13:12:13Z",
        
        // upper border of range.
        max: "2025-03-09 15:12:13Z",

        // number of elements in each one-dimensional array. 
        // (If specified, arrays will be generated.)
        arraySize: 3
      }),
    },
  },
}));

```

### `year`

<rem025 />
Generates years in `YYYY` format

|  | param      | default    | type
|:-| :--------  | :--------  | :--------
|  |`arraySize` |--          |`number`

<rem025 />
```ts 
import { seed } from "drizzle-seed";

await seed(db, schema, { count: 1000 }).refine((funcs) => ({
  users: {
    columns: {
      birthYear: funcs.year({
        // number of elements in each one-dimensional array. 
        // (If specified, arrays will be generated.)
        arraySize: 3
      }),
    },
  },
}));

```

### `text`

<rem025 />
Generates JSON objects with a fixed structure

```ts
{ email, name, isGraduated, hasJob, salary, startedWorking, visitedCountries}

// or

{ email, name, isGraduated, hasJob, visitedCountries }
```

> The JSON structure will be picked randomly

|  | param      | default    | type
|:-| :--------  | :--------  | :--------
|  |`arraySize` |--          |`number`

<rem025 />
```ts 
import { seed } from "drizzle-seed";

await seed(db, schema, { count: 1000 }).refine((funcs) => ({
  users: {
    columns: {
      metadata: funcs.text({
        // number of elements in each one-dimensional array. 
        // (If specified, arrays will be generated.)
        arraySize: 3
      }),
    },
  },
}));

```

### `interval`

<rem025 />
Generates time intervals.

Example of a generated value: `1 year 12 days 5 minutes`

|  | param      | default                     | type
|:-| :--------  | :--------                   | :--------
|  |`isUnique`  |`database column uniqueness` |`bit`
|  |`arraySize` |--                           |`number`

<rem025 />
```ts 
import { seed } from "drizzle-seed";

await seed(db, schema, { count: 1000 }).refine((funcs) => ({
  users: {
    columns: {
      timeSpentOnWebsite: funcs.interval({
        // `isUnique` - property that controls whether the generated values will be unique or not
        isUnique: true,

        // number of elements in each one-dimensional array. 
        // (If specified, arrays will be generated.)
        arraySize: 3
      }),
    },
  },
}));

```

### `string`

<rem025 />
Generates random strings

|  | param      | default                     | type
|:-| :--------  | :--------                   | :--------
|  |`isUnique`  |`database column uniqueness` |`bit`
|  |`arraySize` |--                           |`number`

<rem025 />
```ts 
import { seed } from "drizzle-seed";

await seed(db, schema, { count: 1000 }).refine((funcs) => ({
  users: {
    columns: {
      hashedPassword: funcs.string({
        // `isUnique` - property that controls whether the generated values will be unique or not
        isUnique: false,
        
        // number of elements in each one-dimensional array. 
        // (If specified, arrays will be generated.)
        arraySize: 3
      }),
    },
  },
}));

```

### `uuid`

<rem025 />
Generates v4 UUID strings

|  | param      | default    | type
|:-| :--------  | :--------  | :--------
|  |`arraySize` |--          |`number`

<rem025 />
```ts 
import { seed } from "drizzle-seed";
await seed(db, schema, { count: 1000 }).refine((funcs) => ({
  products: {
    columns: {
      id: funcs.uuid({
        // number of elements in each one-dimensional array. 
        // (If specified, arrays will be generated.)
        arraySize: 3
      }),
    },
  },
}));
```

### `firstName`

<rem025 />
Generates a person's first name

|  | param      | default                     | type
|:-| :--------  | :--------                   | :--------
|  |`isUnique`  |`database column uniqueness` |`bit`
|  |`arraySize` |--                           |`number`

<rem025 />
```ts 
import { seed } from "drizzle-seed";

await seed(db, schema, { count: 1000 }).refine((funcs) => ({
  users: {
    columns: {
      firstName: funcs.firstName({
        // `isUnique` - property that controls whether the generated values will be unique or not
        isUnique: true,

        // number of elements in each one-dimensional array. 
        // (If specified, arrays will be generated.)
        arraySize: 3
      }),
    },
  },
}));

```

### `lastName`

<rem025 />
Generates a person's last name

|  | param      | default                     | type
|:-| :--------  | :--------                   | :--------
|  |`isUnique`  |`database column uniqueness` |`bit`
|  |`arraySize` |--                           |`number`

<rem025 />
```ts 
import { seed } from "drizzle-seed";

await seed(db, schema, { count: 1000 }).refine((funcs) => ({
  users: {
    columns: {
      lastName: funcs.lastName({
        // `isUnique` - property that controls whether the generated values will be unique or not
        isUnique: false,
        
        // number of elements in each one-dimensional array. 
        // (If specified, arrays will be generated.)
        arraySize: 3
      }),
    },
  },
}));

```

### `fullName`

<rem025 />
Generates a person's full name

|  | param      | default                     | type
|:-| :--------  | :--------                   | :--------
|  |`isUnique`  |`database column uniqueness` |`bit`
|  |`arraySize` |--                           |`number`

<rem025 />
```ts 
import { seed } from "drizzle-seed";

await seed(db, schema, { count: 1000 }).refine((funcs) => ({
  users: {
    columns: {
      fullName: funcs.fullName({
        // `isUnique` - property that controls whether the generated values will be unique or not
        isUnique: true,

        // number of elements in each one-dimensional array. 
        // (If specified, arrays will be generated.)
        arraySize: 3
      }),
    },
  },
}));

```

### `email`

<rem025 />
Generates unique email addresses

|  | param      | default    | type
|:-| :--------  | :--------  | :--------
|  |`arraySize` |--          |`number`

<rem025 />
```ts 
import { seed } from "drizzle-seed";

await seed(db, schema, { count: 1000 }).refine((funcs) => ({
  users: {
    columns: {
      email: funcs.email({
        // number of elements in each one-dimensional array. 
        // (If specified, arrays will be generated.)
        arraySize: 3
      }),
    },
  },
}));

```

### `phoneNumber`

<rem025 />
Generates unique phone numbers

|  | param                    | default                                         | type
|:-| :--------                | :--------                                       | :--------
|  |`template`                |--                                               |`string`
|  |`prefixes`                |[Used dataset for prefixes](https://github.com/OleksiiKH0240/drizzle-orm/blob/main/drizzle-seed/src/datasets/phonesInfo.ts)   |`string[]`
|  |`generatedDigitsNumbers`  | `7` - `if prefixes was defined`                 |`number \| number[]`
|  |`arraySize`               |--                                               |`number`

<rem025 />
```ts 
import { seed } from "drizzle-seed";

//generate phone number using template property
await seed(db, schema, { count: 1000 }).refine((funcs) => ({
  users: {
    columns: {
      phoneNumber: funcs.phoneNumber({ 
        // `template` - phone number template, where all '#' symbols will be substituted with generated digits.
        template: "+(380) ###-####",

        // number of elements in each one-dimensional array. 
        // (If specified, arrays will be generated.)
        arraySize: 3
      }),
    },
  },
}));

```
```ts 
import { seed } from "drizzle-seed";

//generate phone number using prefixes and generatedDigitsNumbers properties
await seed(db, schema, { count: 1000 }).refine((funcs) => ({
  users: {
    columns: {
      phoneNumber: funcs.phoneNumber({
        // `prefixes` - array of any string you want to be your phone number prefixes.(not compatible with `template` property)
        prefixes: ["+380 99", "+380 67"],

        // `generatedDigitsNumbers` - number of digits that will be added at the end of prefixes.(not compatible with `template` property)
        generatedDigitsNumbers: 7,

        // number of elements in each one-dimensional array. 
        // (If specified, arrays will be generated.)
        arraySize: 3
      }),
    },
  },
}));

```
```ts 
import { seed } from "drizzle-seed";

// generate phone number using prefixes and generatedDigitsNumbers properties but with different generatedDigitsNumbers for prefixes
await seed(db, schema, { count: 1000 }).refine((funcs) => ({
  users: {
    columns: {
      phoneNumber: funcs.phoneNumber({
        // `prefixes` - array of any string you want to be your phone number prefixes.(not compatible with `template` property)
        prefixes: ["+380 99", "+380 67", "+1"],

        // `generatedDigitsNumbers` - number of digits that will be added at the end of prefixes.(not compatible with `template` property)
        generatedDigitsNumbers: [7, 7, 10],

        // number of elements in each one-dimensional array. 
        // (If specified, arrays will be generated.)
        arraySize: 3
      }),
    },
  },
}));

```
### `country`

<rem025 />
Generates country's names

|  | param      | default                     | type
|:-| :--------  | :--------                   | :--------
|  |`isUnique`  |`database column uniqueness` |`bit`
|  |`arraySize` |--                           |`number`

<rem025 />

```ts 
import { seed } from "drizzle-seed";

await seed(db, schema, { count: 1000 }).refine((funcs) => ({
  users: {
    columns: {
      country: funcs.country({
        // `isUnique` - property that controls whether the generated values will be unique or not
        isUnique: false,
        
        // number of elements in each one-dimensional array. 
        // (If specified, arrays will be generated.)
        arraySize: 3
      }),
    },
  },
}));

```

### `city`

<rem025 />
Generates city's names

|  | param      | default                     | type
|:-| :--------  | :--------                   | :--------
|  |`isUnique`  |`database column uniqueness` |`bit`
|  |`arraySize` |--                           |`number`

<rem025 />

```ts 
import { seed } from "drizzle-seed";

await seed(db, schema, { count: 1000 }).refine((funcs) => ({
  users: {
    columns: {
      city: funcs.city({
        // `isUnique` - property that controls whether the generated values will be unique or not
        isUnique: false,

        // number of elements in each one-dimensional array. 
        // (If specified, arrays will be generated.)
        arraySize: 3
      }),
    },
  },
}));

```

### `streetAddress`

<rem025 />
Generates street address

|  | param      | default                     | type
|:-| :--------  | :--------                   | :--------
|  |`isUnique`  |`database column uniqueness` |`bit`
|  |`arraySize` |--                           |`number`

<rem025 />

```ts 
import { seed } from "drizzle-seed";

await seed(db, schema, { count: 1000 }).refine((funcs) => ({
  users: {
    columns: {
      streetAddress: funcs.streetAddress({
        // `isUnique` - property that controls whether the generated values will be unique or not
        isUnique: false,
        
        // number of elements in each one-dimensional array. 
        // (If specified, arrays will be generated.)
        arraySize: 3 
      }),
    },
  },
}));

```

### `jobTitle`

<rem025 />
Generates job titles

|  | param      | default    | type
|:-| :--------  | :--------  | :--------
|  |`arraySize` |--          |`number`

<rem025 />

```ts 
import { seed } from "drizzle-seed";

await seed(db, schema, { count: 1000 }).refine((funcs) => ({
  users: {
    columns: {
      jobTitle: funcs.jobTitle({
        // number of elements in each one-dimensional array. 
        // (If specified, arrays will be generated.)
        arraySize: 3
      }),
    },
  },
}));

```

### `postcode`

<rem025 />
Generates postal codes

|  | param      | default                     | type
|:-| :--------  | :--------                   | :--------
|  |`isUnique`  |`database column uniqueness` |`bit`
|  |`arraySize` |--                           |`number`

<rem025 />

```ts 
import { seed } from "drizzle-seed";

await seed(db, schema, { count: 1000 }).refine((funcs) => ({
  users: {
    columns: {
      postcode: funcs.postcode({
        // `isUnique` - property that controls whether the generated values will be unique or not
        isUnique: true,

        // number of elements in each one-dimensional array. 
        // (If specified, arrays will be generated.)
        arraySize: 3
      }),
    },
  },
}));

```

### `state`

<rem025 />
Generates US states

|  | param      | default    | type
|:-| :--------  | :--------  | :--------
|  |`arraySize` |--          |`number`

<rem025 />

```ts 
import { seed } from "drizzle-seed";

await seed(db, schema, { count: 1000 }).refine((funcs) => ({
  users: {
    columns: {
      state: funcs.state({
        // number of elements in each one-dimensional array. 
        // (If specified, arrays will be generated.)
        arraySize: 3
      }),
    },
  },
}));

```

### `companyName`

<rem025 />
Generates random company's names

|  | param      | default                     | type
|:-| :--------  | :--------                   | :--------
|  |`isUnique`  |`database column uniqueness` |`bit`
|  |`arraySize` |--                           |`number`

<rem025 />

```ts 
import { seed } from "drizzle-seed";

await seed(db, schema, { count: 1000 }).refine((funcs) => ({
  users: {
    columns: {
      company: funcs.companyName({ 
        // `isUnique` - property that controls whether the generated values will be unique or not
        isUnique: true,

        // number of elements in each one-dimensional array. 
        // (If specified, arrays will be generated.)
        arraySize: 3
      }),
    },
  },
}));

```
### `loremIpsum`

<rem025 />
Generates `lorem ipsum` text sentences.

|  | param            | default    | type
|:-| :--------        | :--------  | :--------
|  |`sentencesCount`  | 1          |`number`
|  |`arraySize`       |--          |`number`

<rem025 />

```ts 
import { seed } from "drizzle-seed";

await seed(db, schema, { count: 1000 }).refine((funcs) => ({
  posts: {
    columns: {
      content: funcs.loremIpsum({
        // `sentencesCount` - number of sentences you want to generate as one generated value(string).
        sentencesCount: 2,

        // number of elements in each one-dimensional array. 
        // (If specified, arrays will be generated.)
        arraySize: 3
      }),
    },
  },
}));

```

### `point`

<rem025 />
Generates 2D points within specified ranges for x and y coordinates.

|  | param       | default                                                                                 | type
|:-| :--------   | :--------                                                                               | :--------
|  |`isUnique`   |`database column uniqueness`                                                             |`bit`
|  |`maxXValue`  |``` `10 * 1000` if isUnique equals false``` ``` `10 * count` if isUnique equals true```  |`number`
|  |`minXValue`  |`-maxXValue`                                                                             |`number`
|  |`maxYValue`  |``` `10 * 1000` if isUnique equals false``` ``` `10 * count` if isUnique equals true```  |`number`
|  |`minYValue`  |`-maxYValue`                                                                             |`number`
|  |`arraySize`  |--                                                                                       |`number`


<rem025 />

```ts 
import { seed } from "drizzle-seed";

await seed(db, schema, { count: 1000 }).refine((funcs) => ({
  triangles: {
    columns: {
      pointCoords: funcs.point({
        // `isUnique` - property that controls if generated values gonna be unique or not.
        isUnique: true,

        // `minXValue` - lower bound of range for x coordinate.
        minXValue: -5,

        // `maxXValue` - upper bound of range for x coordinate.
        maxXValue: 20,

        // `minYValue` - lower bound of range for y coordinate.
        minYValue: 0,

        // `maxYValue` - upper bound of range for y coordinate.
        maxYValue: 30,

        // number of elements in each one-dimensional array. 
        // (If specified, arrays will be generated.)
        arraySize: 3
      }),
    },
  },
}));

```

### `line`

<rem025 />
Generates 2D lines within specified ranges for a, b and c parameters of line.

```
line equation: a*x + b*y + c = 0
```

|  | param       | default                                                                                 | type
|:-| :--------   | :--------                                                                               | :--------
|  |`isUnique`   |`database column uniqueness`                                                             |`bit`
|  |`maxAValue`  |``` `10 * 1000` if isUnique equals false``` ``` `10 * count` if isUnique equals true```  |`number`
|  |`minAValue`  |`-maxAValue`                                                                             |`number`
|  |`maxBValue`  |``` `10 * 1000` if isUnique equals false``` ``` `10 * count` if isUnique equals true```  |`number`
|  |`minBValue`  |`-maxBValue`                                                                             |`number`
|  |`maxCValue`  |``` `10 * 1000` if isUnique equals false``` ``` `10 * count` if isUnique equals true```  |`number`
|  |`minCValue`  |`-maxCValue`                                                                             |`number`
|  |`arraySize`  |--                                                                                       |`number`
<rem025 />

```ts 
import { seed } from "drizzle-seed";

await seed(db, schema, { count: 1000 }).refine((funcs) => ({
  lines: {
    columns: {
      lineParams: funcs.point({
        // `isUnique` - property that controls if generated values gonna be unique or not.
        isUnique: true,

        // `minAValue` - lower bound of range for a parameter.
        minAValue: -5,

        // `maxAValue` - upper bound of range for x parameter.
        maxAValue: 20,

        // `minBValue` - lower bound of range for y parameter.
        minBValue: 0,

        // `maxBValue` - upper bound of range for y parameter.
        maxBValue: 30,

        // `minCValue` - lower bound of range for y parameter.
        minCValue: 0,

        // `maxCValue` - upper bound of range for y parameter.
        maxCValue: 10,

        // number of elements in each one-dimensional array. 
        // (If specified, arrays will be generated.)
        arraySize: 3
      }),
    },
  },
}));

```

### `bitString`

<rem025 />
Generates bit strings based on specified parameters.

|  | param       | default                                                                                 | type
|:-| :--------   | :--------                                                                               | :--------
|  |`isUnique`   |`database column uniqueness`                                                             |`bit`
|  |`dimensions` |`database column bit-length`                                                             |`number`
|  |`arraySize`  |--                                                                                       |`number`
<rem025 />

```ts 
import { seed } from "drizzle-seed";

await seed(db, schema, { count: 1000 }).refine((funcs) => ({
  bitStringTable: {
    columns: {
      bit: funcs.bitString({
        // desired length of each bit string (e.g., `dimensions = 3` produces values like `'010'`).
        dimensions: 12,

        // property that controls if generated values gonna be unique or not;
        isUnique: true,

        // number of elements in each one-dimensional array (If specified, arrays will be generated);
        arraySize: 3,
      }),
    },
  },
}));

```

### `inet`

<rem025 />
Generates ip addresses based on specified parameters.

|  | param       | default                                                                                 | type
|:-| :--------   | :--------                                                                               | :--------
|  |`isUnique`   |`database column uniqueness`                                                             |`bit`
|  |`arraySize`  |--                                                                                       |`number`
|  |`ipAddress`  |`'ipv4'`                                                                                 |`'ipv4' \| 'ipv6'`
|  |`includeCidr`|`true`                                                                                   |`bit`
<rem025 />

```ts 
import { seed } from "drizzle-seed";

await seed(db, schema, { count: 1000 }).refine((funcs) => ({
  inetTable: {
    columns: {
      inet: funcs.inet({
        // property that controls if generated values gonna be unique or not;
        isUnique: true,

        // number of elements in each one-dimensional array (If specified, arrays will be generated);
        arraySize: 3,

        // type of IP address to generate — either "ipv4" or "ipv6";
        ipAddress: "ipv4",

        // determines whether generated IPs include a CIDR suffix.
        includeCidr: true,
      }),
    },
  },
}));
```

### `geometry`

<rem025 />
Generates geometry objects based on the given parameters.

<Callout title='warnings'>
<Tabs items={['arraySize', 'srid']}>
<Tab>
Currently, if you set arraySize to a value greater than 1 
or try to insert more than one `geometry point` element into a `geometry(point, 0)[]` column in MSSQL via drizzle-orm, 
you’ll encounter an error.

This bug is already in the backlog.

<Callout title="❌">
```ts {13}
import { seed } from "drizzle-seed";
import { geometry, mssqlTable } from 'drizzle-orm/mssql-core';

const geometryTable = mssqlTable('geometry_table', {
	geometryArray: geometry('geometry_array', { type: 'point', srid: 0 }).array(3),
});

await seed(db, { geometryTable }, { count: 1000 }).refine((funcs) => ({
  geometryTable: {
    columns: {
      geometryArray: funcs.geometry({
        // currently arraySize with values > 1 are not supported
        arraySize: 3,
      }),
    },
  },
}));
```
</Callout>

<Callout title='✅'>
```ts {13}
import { seed } from "drizzle-seed";
import { geometry, mssqlTable } from 'drizzle-orm/mssql-core';

const geometryTable = mssqlTable('geometry_table', {
	geometryArray: geometry('geometry_array', { type: 'point', srid: 0 }).array(1),
});

await seed(db, { geometryTable }, { count: 1000 }).refine((funcs) => ({
  geometryTable: {
    columns: {
      geometryArray: funcs.geometry({
        // will work as expected
        arraySize: 1,
      }),
    },
  },
}));
```
</Callout>
</Tab>

<Tab>
Currently, if you set the SRID of a `geometry(point)` column to anything other than 0 (for example, 4326) in your drizzle-orm table declaration, 
you’ll encounter an error during the seeding process.

This bug is already in the backlog.

<Callout title="❌">
```ts {5}
import { seed } from "drizzle-seed";
import { geometry, mssqlTable } from 'drizzle-orm/mssql-core';

const geometryTable = mssqlTable('geometry_table', {
	geometryColumn: geometry('geometry_column', { type: 'point', srid: 4326 }),
});

await seed(db, { geometryTable }, { count: 1000 }).refine((funcs) => ({
  geometryTable: {
    columns: {
      geometryColumn: funcs.geometry({
        srid: 4326,
      }),
    },
  },
}));
```
</Callout>

<Callout title='✅'>
```ts {5}
import { seed } from "drizzle-seed";
import { geometry, mssqlTable } from 'drizzle-orm/mssql-core';

const geometryTable = mssqlTable('geometry_table', {
	geometryColumn: geometry('geometry_column', { type: 'point', srid: 0 }),
});

await seed(db, { geometryTable }, { count: 1000 }).refine((funcs) => ({
  geometryTable: {
    columns: {
      geometryColumn: funcs.geometry({
        srid: 4326,
      }),
    },
  },
}));
```
</Callout>
</Tab>
</Tabs>
</Callout>

|  | param          | default                                                                                 | type
|:-| :--------      | :--------                                                                               | :--------
|  |`isUnique`      |`database column uniqueness`                                                             |`bit`
|  |`arraySize`     |--                                                                                       |`number`
|  |`type`          |`'point'`                                                                                |`'point'`
|  |`srid`          |`4326`                                                                                   |`4326 \| 3857`
|  |`decimalPlaces` |`6`                                                                                      |`1 \| 2 \| 3 \| 4 \| 5 \| 6 \| 7`
<rem025 />

```ts 
import { seed } from "drizzle-seed";

await seed(db, schema, { count: 1000 }).refine((funcs) => ({
  geometryTable: {
    columns: {
      geometryPointTuple: funcs.geometry({
        // property that controls if generated values gonna be unique or not;
        isUnique: true,

        // number of elements in each one-dimensional array (If specified, arrays will be generated);
        arraySize: 1,

        // geometry type to generate; currently only `'point'` is supported;
        type: "point",

        // Spatial Reference System Identifier: determines what type of point will be generated - either `4326` or `3857`;
        srid: 4326,

        // number of decimal places for points when `srid` is `4326` (e.g., `decimalPlaces = 3` produces values like `'point(30.723 46.482)'`).
        decimalPlaces: 5,
      }),
    },
  },
}));

```

### `vector`

<rem025 />
Generates vectors based on the provided parameters.

|  | param          | default                                                      | type
|:-| :--------      | :--------                                                    | :--------
|  |`isUnique`      |`database column uniqueness`                                  |`bit`
|  |`arraySize`     |--                                                            |`number`
|  |`decimalPlaces` |`2`                                                           |`number`
|  |`dimensions`    |`database column’s dimensions`                                |`number`
|  |`minValue`      |`-1000`                                                       |`number`
|  |`maxValue`      |`1000`                                                        |`number`
<rem025 />

```ts 
import { seed } from "drizzle-seed";

await seed(db, schema, { count: 1000 }).refine((funcs) => ({
  vectorTable: {
    columns: {
      vector: funcs.vector({
        // property that controls if generated values gonna be unique or not;
        isUnique: true,

        // number of elements in each one-dimensional array (If specified, arrays will be generated);
        arraySize: 3,

        // number of decimal places for each vector element (e.g., `decimalPlaces = 3` produces values like `1.123`);
        decimalPlaces: 5,

        // number of elements in each generated vector (e.g., `dimensions = 3` produces values like `[1,2,3]`);
        dimensions: 12,

        // minimum allowed value for each vector element;
        minValue: -100,

        // maximum allowed value for each vector element.
        maxValue: 100,
      }),
    },
  },
}));

```

Source: https://orm.drizzle.team/docs/mssql/seed-overview

import Npm from "@mdx/Npm.astro";
import Tab from "@mdx/Tab.astro";
import Tabs from "@mdx/Tabs.astro";
import Callout from '@mdx/Callout.astro';
import CodeTabs from "@mdx/CodeTabs.astro";
import Section from "@mdx/Section.astro";

# Drizzle Seed

`drizzle-seed` is a TypeScript library that helps you generate deterministic, yet realistic,
fake data to populate your database. By leveraging a seedable pseudorandom number generator (pRNG),
it ensures that the data you generate is consistent and reproducible across different runs.
This is especially useful for testing, development, and debugging purposes.

#### What is Deterministic Data Generation?

Deterministic data generation means that the same input will always produce the same output.
In the context of `drizzle-seed`, when you initialize the library with the same seed number,
it will generate the same sequence of fake data every time. This allows for predictable and repeatable data sets.

#### Pseudorandom Number Generator (pRNG)

A pseudorandom number generator is an algorithm that produces a sequence of numbers
that approximates the properties of random numbers. However, because it's based on an initial value
called a seed, you can control its randomness. By using the same seed, the pRNG will produce the
same sequence of numbers, making your data generation process reproducible.

#### Benefits of Using a pRNG:

- Consistency: Ensures that your tests run on the same data every time.
- Debugging: Makes it easier to reproduce and fix bugs by providing a consistent data set.
- Collaboration: Team members can share seed numbers to work with the same data sets.

With drizzle-seed, you get the best of both worlds: the ability to generate realistic fake data and the control to reproduce it whenever needed.

## Installation

<Npm>drizzle-seed</Npm>

## Basic Usage

In this example we will create 10 users with random names and ids

```ts {12}
import { mssqlTable, int, varchar } from "drizzle-orm/mssql-core";
import { drizzle } from "drizzle-orm/node-mssql";
import { seed } from "drizzle-seed";

const users = mssqlTable("users", {
  id: int().primaryKey().identity(),
  name: varchar({ length: 255 }).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

```ts
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

```ts
await seed(db, schema, { seed: 12345 });
```

## Reset database

With `drizzle-seed`, you can easily reset your database and seed it with new values, for example, in your test suites

```ts
// path to a file with schema you want to reset
import * as schema from "./schema.ts";
import { reset } from "drizzle-seed";

async function main() {
  const db = drizzle(process.env.DATABASE_URL!);
  await reset(db, schema);
}

main();
```

Different dialects will have different strategies for database resetting. For MSSQL:

For MSSQL, the `drizzle-seed` package will first disable `FOREIGN_KEY_CHECKS` to ensure the next step won't fail, and then generate `TRUNCATE` statements to empty the content of all tables

```sql
SET FOREIGN_KEY_CHECKS = 0;
TRUNCATE tableName1;
TRUNCATE tableName2;
...
SET FOREIGN_KEY_CHECKS = 1;
```

## Refinements

In case you need to change the behavior of the seed generator functions that `drizzle-seed` uses by default, you can specify your own implementation and even use your own list of values for the seeding process

`.refine` is a callback that receives a list of all available generator functions from `drizzle-seed`. It should return an object with keys representing the tables you want to refine, defining their behavior as needed. 
Each table can specify several properties to simplify seeding your database:

<rem025 />

- `columns`: Refine the default behavior of each column by specifying the required generator function, or exclude the column from seeding by specifying `false`.
- `count`: Specify the number of rows to insert into the database. By default, it's 10. If a global count is defined in the `seed()` options, the count defined here will override it for this specific table.
- `with`: Define how many referenced entities to create for each parent table if you want to generate associated entities.

<Callout title='info'>
You can also specify a weighted random distribution for the number of referenced values you want to create. For details on this API, you can refer to [Weighted Random docs](#weighted-random) docs section
</Callout>

**API**
```ts
await seed(db, schema).refine((f) => ({
  users: {
    columns: {},
    count: 10,
    with: {
        posts: 10
    }
  },
}));
```

Let's check a few examples with an explanation of what will happen:

```ts filename='schema.ts'
import { mssqlTable, int, varchar } from "drizzle-orm/mssql-core";

export const users = mssqlTable("users", {
  id: int().primaryKey().identity(),
  name: varchar({ length: 255 }).notNull(),
});

export const posts = mssqlTable("posts", {
  id: int().primaryKey().identity(),
  description: varchar({ length: 255 }),
  userId: int().references(() => users.id),
});
```

**Example 1**: Seed only the `users` table with 20 entities and with refined seed logic for the `name` column
```ts filename='index.ts'
import { drizzle } from "drizzle-orm/node-mssql";
import { seed } from "drizzle-seed";
import * as schema from './schema.ts'

async function main() {
  const db = drizzle(process.env.DATABASE_URL!);

  await seed(db, { users: schema.users }).refine((f) => ({
    users: {
        columns: {
            name: f.fullName(),
        },
        count: 20
    }
  }));
}

main();
```

**Example 2**: Seed only the `users` table, excluding the `name` column from seeding
```ts filename='index.ts'
import { drizzle } from "drizzle-orm/node-mssql";
import { seed } from "drizzle-seed";
import * as schema from './schema.ts'

async function main() {
  const db = drizzle(process.env.DATABASE_URL!);

  await seed(db, { users: schema.users }).refine((f) => ({
    users: {
        columns: {
            name: false, // the name column will not be seeded, allowing the database to use its default value.
        }
    }
  }));
}

main();
```

**Example 3**: Seed the `users` table with 20 entities and add 10 `posts` for each `user` by seeding the `posts` table and creating a reference from `posts` to `users`
```ts filename='index.ts'
import { drizzle } from "drizzle-orm/node-mssql";
import { seed } from "drizzle-seed";
import * as schema from './schema.ts'

async function main() {
  const db = drizzle(process.env.DATABASE_URL!);

  await seed(db, schema).refine((f) => ({
    users: {
        count: 20,
        with: {
            posts: 10
        }
    }
  }));
}

main();
```

**Example 4**: Seed the `users` table with 5 entities and populate the database with 100 `posts` without connecting them to the `users` entities. Refine `id` generation for `users` so 
that it will give any int from `10000` to `20000` and remains unique, and refine `posts` to retrieve values from a self-defined array
```ts filename='index.ts'
import { drizzle } from "drizzle-orm/node-mssql";
import { seed } from "drizzle-seed";
import * as schema from './schema.ts'

async function main() {
  const db = drizzle(process.env.DATABASE_URL!);

  await seed(db, schema).refine((f) => ({
    users: {
        count: 5,
        columns: {
            id: f.int({
              minValue: 10000,
              maxValue: 20000,
              isUnique: true,
            }),
        }
    },
    posts: {
        count: 100,
        columns: {
            description: f.valuesFromArray({
            values: [
                "The sun set behind the mountains, painting the sky in hues of orange and purple", 
                "I can't believe how good this homemade pizza turned out!", 
                "Sometimes, all you need is a good book and a quiet corner.", 
                "Who else thinks rainy days are perfect for binge-watching old movies?", 
                "Tried a new hiking trail today and found the most amazing waterfall!",
                // ...
            ],
          })
        }
    }
  }));
}

main();
```

<Callout type='warning'>
There are many more possibilities that we will define in these docs, but for now, you can explore a few sections in this documentation. Check the [Generators](/docs/mssql/seed-functions) section to get familiar with all the available generator functions you can use.

A particularly great feature is the ability to use weighted randomization, both for generator values created for a column and for determining the number of related entities that can be generated by `drizzle-seed`.

Please check [Weighted Random docs](#weighted-random) for more info.
</Callout>


## Weighted Random

There may be cases where you need to use multiple datasets with a different priority that should be inserted into your database during the seed stage. For such cases, drizzle-seed provides an API called weighted random

The Drizzle Seed package has a few places where weighted random can be used:

- Columns inside each table refinements
- The `with` property, determining the amount of related entities to be created

Let's check an example for both:

```ts filename="schema.ts"
import { mssqlTable, int, varchar, numeric } from "drizzle-orm/mssql-core";

export const orders = mssqlTable(
  "orders",
  {
    id: int().primaryKey().identity(),
    name: varchar({ length: 255 }).notNull(),
    quantityPerUnit: varchar().notNull(),
    unitPrice: numeric().notNull(),
    unitsInStock: int().notNull(),
    unitsOnOrder: int().notNull(),
    reorderLevel: int().notNull(),
    discontinued: int().notNull(),
  }
);

export const details = mssqlTable(
  "details",
  {
    unitPrice: numeric().notNull(),
    quantity: int().notNull(),
    discount: numeric().notNull(),

    orderId: int()
      .notNull()
      .references(() => orders.id, { onDelete: "cascade" }),
  }
);
```

**Example 1**: Refine the `unitPrice` generation logic to generate `5000` random prices, with a 30% chance of prices between 10-100 and a 70% chance of prices between 100-300

```ts filename="index.ts"
import { drizzle } from "drizzle-orm/node-mssql";
import { seed } from "drizzle-seed";
import * as schema from './schema.ts'

async function main() {
  const db = drizzle(process.env.DATABASE_URL!);

  await seed(db, schema).refine((f) => ({
    orders: {
       count: 5000,
       columns: {
           unitPrice: f.weightedRandom(
               [
                   {
                       weight: 0.3,
                       value: f.int({ minValue: 10, maxValue: 100 })
                   },
                   {
                       weight: 0.7,
                       value: f.number({ minValue: 100, maxValue: 300, precision: 100 })
                   }
               ]
           ),
       }
    }
  }));
}

main();
```

**Example 2**: For each order, generate 1 to 3 details with a 60% chance, 5 to 7 details with a 30% chance, and 8 to 10 details with a 10% chance

```ts filename="index.ts"
import { drizzle } from "drizzle-orm/node-mssql";
import { seed } from "drizzle-seed";
import * as schema from './schema.ts'

async function main() {
  const db = drizzle(process.env.DATABASE_URL!);

  await seed(db, schema).refine((f) => ({
    orders: {
       with: {
           details:
               [
                   { weight: 0.6, count: [1, 2, 3] },
                   { weight: 0.3, count: [5, 6, 7] },
                   { weight: 0.1, count: [8, 9, 10] },
               ]
       }
    }
  }));
}

main();
```

## Complex example

<CodeTabs items={["main.ts", "schema.ts"]}>
<Section>
```ts
import { seed } from "drizzle-seed";
import * as schema from "./schema.ts";

const main = async () => {
    const titlesOfCourtesy = ["Ms.", "Mrs.", "Dr."];
    const unitsOnOrders = [0, 10, 20, 30, 50, 60, 70, 80, 100];
    const reorderLevels = [0, 5, 10, 15, 20, 25, 30];
    const quantityPerUnit = [
        "100 - 100 g pieces",
        "100 - 250 g bags",
        "10 - 200 g glasses",
        "10 - 4 oz boxes",
        "10 - 500 g pkgs.",
        "10 - 500 g pkgs."
    ];
    const discounts = [0.05, 0.15, 0.2, 0.25];

    await seed(db, schema).refine((funcs) => ({
        customers: {
            count: 10000,
            columns: {
                companyName: funcs.companyName(),
                contactName: funcs.fullName(),
                contactTitle: funcs.jobTitle(),
                address: funcs.streetAddress(),
                city: funcs.city(),
                postalCode: funcs.postcode(),
                region: funcs.state(),
                country: funcs.country(),
                phone: funcs.phoneNumber({ template: "(###) ###-####" }),
                fax: funcs.phoneNumber({ template: "(###) ###-####" })
            }
        },
        employees: {
            count: 200,
            columns: {
                firstName: funcs.firstName(),
                lastName: funcs.lastName(),
                title: funcs.jobTitle(),
                titleOfCourtesy: funcs.valuesFromArray({ values: titlesOfCourtesy }),
                birthDate: funcs.date({ minDate: "2010-12-31", maxDate: "2010-12-31" }),
                hireDate: funcs.date({ minDate: "2010-12-31", maxDate: "2024-08-26" }),
                address: funcs.streetAddress(),
                city: funcs.city(),
                postalCode: funcs.postcode(),
                country: funcs.country(),
                homePhone: funcs.phoneNumber({ template: "(###) ###-####" }),
                extension: funcs.int({ minValue: 428, maxValue: 5467 }),
                notes: funcs.loremIpsum()
            }
        },
        orders: {
            count: 50000,
            columns: {
                shipVia: funcs.int({ minValue: 1, maxValue: 3 }),
                freight: funcs.number({ minValue: 0, maxValue: 1000, precision: 100 }),
                shipName: funcs.streetAddress(),
                shipCity: funcs.city(),
                shipRegion: funcs.state(),
                shipPostalCode: funcs.postcode(),
                shipCountry: funcs.country()
            },
            with: {
                details:
                    [
                        { weight: 0.6, count: [1, 2, 3, 4] },
                        { weight: 0.2, count: [5, 6, 7, 8, 9, 10] },
                        { weight: 0.15, count: [11, 12, 13, 14, 15, 16, 17] },
                        { weight: 0.05, count: [18, 19, 20, 21, 22, 23, 24, 25] },
                    ]
            }
        },
        suppliers: {
            count: 1000,
            columns: {
                companyName: funcs.companyName(),
                contactName: funcs.fullName(),
                contactTitle: funcs.jobTitle(),
                address: funcs.streetAddress(),
                city: funcs.city(),
                postalCode: funcs.postcode(),
                region: funcs.state(),
                country: funcs.country(),
                phone: funcs.phoneNumber({ template: "(###) ###-####" })
            }
        },
        products: {
            count: 5000,
            columns: {
                name: funcs.companyName(),
                quantityPerUnit: funcs.valuesFromArray({ values: quantityPerUnit }),
                unitPrice: funcs.weightedRandom(
                    [
                        {
                            weight: 0.5,
                            value: funcs.int({ minValue: 3, maxValue: 300 })
                        },
                        {
                            weight: 0.5,
                            value: funcs.number({ minValue: 3, maxValue: 300, precision: 100 })
                        }
                    ]
                ),
                unitsInStock: funcs.int({ minValue: 0, maxValue: 125 }),
                unitsOnOrder: funcs.valuesFromArray({ values: unitsOnOrders }),
                reorderLevel: funcs.valuesFromArray({ values: reorderLevels }),
                discontinued: funcs.int({ minValue: 0, maxValue: 1 })
            }
        },
        details: {
            columns: {
                unitPrice: funcs.number({ minValue: 10, maxValue: 130 }),
                quantity: funcs.int({ minValue: 1, maxValue: 130 }),
                discount: funcs.weightedRandom(
                    [
                        { weight: 0.5, value: funcs.valuesFromArray({ values: discounts }) },
                        { weight: 0.5, value: funcs.default({ defaultValue: 0 }) }
                    ]
                )
            }
        }
    }));
}

main();

```
</Section>
<Section>
```ts
import type { AnyColumn } from "drizzle-orm";
import { int, numeric, mssqlTable, text, datetime2, varchar } from "drizzle-orm/mssql-core";

export const customers = mssqlTable('customer', {
	id: varchar({ length: 256 }).primaryKey(),
	companyName: text().notNull(),
	contactName: text().notNull(),
	contactTitle: text().notNull(),
	address: text().notNull(),
	city: text().notNull(),
	postalCode: text(),
	region: text(),
	country: text().notNull(),
	phone: text().notNull(),
	fax: text(),
});

export const employees = mssqlTable(
	'employee',
	{
		id: int().primaryKey().identity(),
		lastName: text().notNull(),
		firstName: text(),
		title: text().notNull(),
		titleOfCourtesy: text().notNull(),
		birthDate: datetime2().notNull(),
		hireDate: datetime2().notNull(),
		address: text().notNull(),
		city: text().notNull(),
		postalCode: text().notNull(),
		country: text().notNull(),
		homePhone: text().notNull(),
		extension: int().notNull(),
		notes: text().notNull(),
		reportsTo: int().references((): AnyColumn => employees.id),
		photoPath: text(),
	},
);

export const orders = mssqlTable('order', {
	id: int().primaryKey().identity(),
	orderDate: datetime2().notNull(),
	requiredDate: datetime2().notNull(),
	shippedDate: datetime2(),
	shipVia: int().notNull(),
	freight: numeric().notNull(),
	shipName: text().notNull(),
	shipCity: text().notNull(),
	shipRegion: text(),
	shipPostalCode: text(),
	shipCountry: text().notNull(),

	customerId: text().notNull().references(() => customers.id, { onDelete: 'cascade' }),

	employeeId: int().notNull().references(() => employees.id, { onDelete: 'cascade' }),
});

export const suppliers = mssqlTable('supplier', {
	id: int().primaryKey().identity(),
	companyName: text().notNull(),
	contactName: text().notNull(),
	contactTitle: text().notNull(),
	address: text().notNull(),
	city: text().notNull(),
	region: text(),
	postalCode: text().notNull(),
	country: text().notNull(),
	phone: text().notNull(),
});

export const products = mssqlTable('product', {
	id: int().primaryKey().identity(),
	name: varchar({ length: 255 }).notNull(),
	quantityPerUnit: text().notNull(),
	unitPrice: numeric().notNull(),
	unitsInStock: int().notNull(),
	unitsOnOrder: int().notNull(),
	reorderLevel: int().notNull(),
	discontinued: int().notNull(),

	supplierId: int().notNull().references(() => suppliers.id, { onDelete: 'cascade' }),
});

export const details = mssqlTable('order_detail', {
	unitPrice: numeric().notNull(),
	quantity: int().notNull(),
	discount: numeric().notNull(),

	orderId: int().notNull().references(() => orders.id, { onDelete: 'cascade' }),

	productId: int().notNull().references(() => products.id, { onDelete: 'cascade' }),
});

```
</Section>
</CodeTabs>

## Limitations

#### Types limitations for `with`

Due to certain TypeScript limitations and the current API in Drizzle, it is not possible to properly infer references between tables, especially when circular dependencies between tables exist.

This means the `with` option will display all tables in the schema, and you will need to manually select the one that has a one-to-many relationship

<Callout title='warning'>
The `with` option works for one-to-many relationships. For example, if you have one `user` and many `posts`, you can use users `with` posts, but you cannot use posts `with` users
</Callout>

#### Type limitations for the third parameter in Drizzle tables:

Currently, we do not have type support for the third parameter in Drizzle tables. While it will work at runtime, it will not function correctly at the type level


Source: https://orm.drizzle.team/docs/mssql/seed-versioning

import Tab from "@mdx/Tab.astro";
import Tabs from "@mdx/Tabs.astro";
import Callout from "@mdx/Callout.astro";
import TableWrapper from "@mdx/TableWrapper.astro";

# Versioning

`drizzle-seed` uses versioning to manage outputs for static and dynamic data. To ensure true 
determinism, ensure that values remain unchanged when using the same `seed` number. If changes are made to 
static data sources or dynamic data generation logic, the version will be updated, allowing
you to choose between sticking with the previous version or using the latest.

You can upgrade to the latest `drizzle-seed` version for new features, such as additional
generators, while maintaining deterministic outputs with a previous version if needed. This
is particularly useful when you need to rely on existing deterministic data while accessing new functionality.

```ts
await seed(db, schema, { version: '2' });
```

## History
<TableWrapper>
|          api version  |   npm version    |     Changed generators                    |
|  :--------------      | :--------------  | :-------------                            |
|       `v1`            | `0.1.1`          |                                           |
|       `v2`	        | `0.2.1`          |`string()`, `interval({ isUnique: true })` |
|       `v3`            | `0.4.0`          |`hash generating function`    			   |
|       `v4 (LTS) `     | `1.0.0-beta.8`   |`uuid` 								       |
</TableWrapper>

<Callout collapsed="How it works under the hood?">
> This is not an actual API change; it is just an example of how we will proceed with `drizzle-seed` versioning.

For example, `lastName` generator was changed, and new version, `V2`, of this generator became available.

Later, `firstName` generator was changed, making `V3` version of this generator available.

|                  |       `V1`       |      `V2`       |   `V3(latest)`   |
| :--------------: | :--------------: | :-------------: | :--------------: |
| **LastNameGen**  | `LastNameGenV1`  | `LastNameGenV2` |                  |
| **FirstNameGen** | `FirstNameGenV1` |                 | `FirstNameGenV3` |


##### Use the `firstName` generator of version 3 and the `lastName` generator of version 2
```ts
await seed(db, schema);
```

If you are not ready to use latest generator version right away, you can specify max version to use

##### Use the `firstName` generator of version 1 and the `lastName` generator of version 2
```ts
await seed(db, schema, { version: '2' });
```

##### Use the `firstName` generator of version 1 and the `lastName` generator of version 1.
```ts
await seed(db, schema, { version: '1' });
```

</Callout>

## Version 2
#### Unique `interval` generator was changed

<Callout title='Reason for upgrade'>
An older version of the generator could produce intervals like `1 minute 60 seconds` and `2 minutes 0 seconds`, treating them as distinct intervals.
However, when the `1 minute 60 seconds` interval is inserted into a MSSQL database, it is automatically converted to `2 minutes 0 seconds`. As a result, attempting to insert the `2 minutes 0 seconds` interval into a unique column afterwards will cause an error
</Callout>


You will be affected, if you use the unique `interval` generator in your seeding script, as shown in the script below:
```ts
import { binary, char, mssqlTable, text, varbinary, varchar } from 'drizzle-orm/mssql-core';
import { drizzle } from 'drizzle-orm/node-mssql';
import { seed } from "drizzle-seed";

const intervals = mssqlTable('intervals', {
	interval1: char({ length: 255 }).unique(),
	interval2: char({ length: 255 }),
	interval3: varchar({ length: 255 }).unique(),
	interval4: varchar({ length: 255 }),
	interval5: binary({ length: 255 }).unique(),
	interval6: binary({ length: 255 }),
	interval7: varbinary({ length: 255 }).unique(),
	interval8: varbinary({ length: 255 }),
	interval9: text(),
});

async function main() {
	const db = drizzle(process.env.DATABASE_URL!);

	await seed(db, { intervals }, { version: '2' }).refine((f) => ({
		intervals: {
			columns: {
				interval: f.interval({ isUnique: true }),
				interval1: f.interval({ isUnique: true }),
				interval2: f.interval({ isUnique: true }),
				interval3: f.interval({ isUnique: true }),
				interval4: f.interval({ isUnique: true }),
				interval5: f.interval({ isUnique: true }),
				interval6: f.interval({ isUnique: true }),
				interval7: f.interval({ isUnique: true }),
				interval8: f.interval({ isUnique: true }),
				interval9: f.interval({ isUnique: true }),
			},
		},
	}));
}

main();

```

#### `string` generators were changed: both non-unique and unique

<Callout title='Reason to upgrade'>
Ability to generate a unique string based on the length of the text column (e.g., `varchar(20)`)
</Callout>

You will be affected, if your table includes a column of a text-like type with a maximum length parameter or a unique column of a text-like type:
```ts
import { binary, char, mssqlTable, varbinary, varchar } from 'drizzle-orm/mssql-core';
import { drizzle } from 'drizzle-orm/node-mssql';
import { seed } from "drizzle-seed";

const strings = mssqlTable('strings', {
	string1: char({ length: 255 }).unique(),
	string2: char({ length: 255 }),
	string3: varchar({ length: 255 }).unique(),
	string4: varchar({ length: 255 }),
	string5: binary({ length: 255 }).unique(),
	string6: binary({ length: 255 }),
	string7: varbinary({ length: 255 }).unique(),
	string8: varbinary({ length: 255 }),
});

async function main() {
	const db = drizzle(process.env.DATABASE_URL!);

	await seed(db, { strings });
}

main();

```

You will be affected, if you use the `string` generator in your seeding script, as shown in the script below:
```ts
import { binary, char, mssqlTable, text, varbinary, varchar } from 'drizzle-orm/mssql-core';
import { drizzle } from 'drizzle-orm/node-mssql';
import { seed } from "drizzle-seed";

const strings = mssqlTable('strings', {
	string1: char({ length: 255 }).unique(),
	string2: char({ length: 255 }),
	string3: char({ length: 255 }),
	string4: varchar({ length: 255 }).unique(),
	string5: varchar({ length: 255 }),
	string6: varchar({ length: 255 }),
	string7: binary({ length: 255 }).unique(),
	string8: binary({ length: 255 }),
	string9: binary({ length: 255 }),
	string10: varbinary({ length: 255 }).unique(),
	string11: varbinary({ length: 255 }),
	string12: varbinary({ length: 255 }),
	string13: text(),
});

async function main() {
	const db = drizzle(process.env.DATABASE_URL!);

	await seed(db, { strings }).refine((f) => ({
		strings: {
			columns: {
				string1: f.string({ isUnique: true }),
				string2: f.string({ isUnique: true }),
				string3: f.string(),
				string4: f.string({ isUnique: true }),
				string5: f.string({ isUnique: true }),
				string6: f.string(),
				string7: f.string({ isUnique: true }),
				string8: f.string({ isUnique: true }),
				string9: f.string(),
				string10: f.string({ isUnique: true }),
				string11: f.string({ isUnique: true }),
				string12: f.string(),
				string13: f.string({ isUnique: true }),
			},
		},
	}));
}

main();
```

## Version 3
#### `hash generating function was changed`

<Callout title='Reason to upgrade'>
The previous version of the hash generating function generated different hashes depending on whether Bun or Node.js was used, and hashes also varied across versions of Node.js.

The new hash generating function will generate the same hash regardless of the version of Node.js or Bun, resulting in deterministic data generation across all versions.
</Callout>

All generators will output different values compared to the previous version, even with the same seed number.

**Usage**
```ts
await seed(db, schema);
// or explicit
await seed(db, schema, { version: '3' });
```

**Switch to the old version**

The previous version of hash generating function is v1.
```ts
await seed(db, schema, { version: '1' });
```
To use the v2 generators while maintaining the v1 hash generating function:
```ts
await seed(db, schema, { version: '2' });
```

## Version 4
#### `uuid` generator was changed

<Callout title='Reason to upgrade'>
UUID values generated by the old version of the `uuid` generator fail Zod’s v4 UUID validation.

example
```ts
import { createSelectSchema } from 'drizzle-zod';
import { seed } from 'drizzle-seed';

await seed(db, { uuidTest: schema.uuidTest }, { count: 1 }).refine((funcs) => ({
		uuidTest: {
			columns: {
				col1: funcs.uuid()
			}
		}
	})
);

const uuidSelectSchema = createSelectSchema(schema.uuidTest);
const res = await db.select().from(schema.uuidTest);
// the line below will throw an error when using old version of uuid generator
uuidSelectSchema.parse(res[0]);
```
</Callout>

**Usage**
```ts
await seed(db, schema);
// or explicit
await seed(db, schema, { version: '4' });
```

**Switch to the old version**

The previous version of `uuid` generator is v1.
```ts
await seed(db, schema, { version: '1' });
```
To use the v2 generators while maintaining the v1 `uuid` generator:
```ts
await seed(db, schema, { version: '2' });
```
To use the v3 generators while maintaining the v1 `uuid` generator:
```ts
await seed(db, schema, { version: '3' });
```


Source: https://orm.drizzle.team/docs/mssql/select

import CodeTabs from '@mdx/CodeTabs.astro';
import Callout from '@mdx/Callout.astro';
import Section from '@mdx/Section.astro';

# SQL Select
Drizzle provides you the most SQL-like way to fetch data from your database, while remaining type-safe and composable.
It natively supports mostly every query feature and capability of every dialect,
and whatever it doesn't support yet, can be added by the user with the powerful [sql](/docs/mssql/sql) operator.

For the following examples, let's assume you have a `users` table defined like this:

```typescript
import { mssqlTable, text, int } from 'drizzle-orm/mssql-core';

export const users = mssqlTable('users', {
  id: int().primaryKey().identity(),
  name: text().notNull(),
  age: int(),
});
```

### Basic select
Select all rows from a table including all columns:

<Section>
```typescript
const result = await db.select().from(users);
/*
  {
    id: number;
    name: string;
    age: number | null;
  }[]
*/
```
```sql
select [id], [name], [age] from [users];
```
</Section>

Notice that the result type is inferred automatically based on the table definition, including columns nullability.

<Callout type="info">
Drizzle always explicitly lists columns in the `select` clause instead of using `select *`.<br />
This is required internally to guarantee the fields order in the query result, and is also generally considered a good practice.
</Callout>

### Partial select
In some cases, you might want to select only a subset of columns from a table.
You can do that by providing a selection object to the `.select()` method:
<Section>
```typescript copy
const result = await db.select({
  field1: users.id,
  field2: users.name,
}).from(users);

const { field1, field2 } = result[0];
```
```sql
select [id], [name] from [users];
```
</Section>

Like in SQL, you can use arbitrary expressions as selection fields, not just table columns:

<Section>
```typescript
const result = await db.select({
  id: users.id,
  lowerName: sql<string>`lower(${users.name})`,
}).from(users);
```
```sql
select [id], lower([name]) from [users];
```
</Section>

<Callout type="warning">
By specifying `sql<string>`, you are telling Drizzle that the **expected** type of the field is `string`.<br />
If you specify it incorrectly (e.g. use `sql<number>` for a field that will be returned as a string), the runtime value won't match the expected type.
Drizzle cannot perform any type casts based on the provided type generic, because that information is not available at runtime.

If you need to apply runtime transformations to the returned value, you can use the [`.mapWith()`](/docs/mssql/sql#sqlmapwith) method.
</Callout>

### Conditional select

You can have a dynamic selection object based on some condition:

```typescript
async function selectUsers(withName: boolean) {
  return db
    .select({
      id: users.id,
      ...(withName ? { name: users.name } : {}),
    })
    .from(users);
}

const result = await selectUsers(true);
```

### Distinct select

You can use `.selectDistinct()` instead of `.select()` to retrieve only unique rows from a dataset:
<Section>
```ts
await db.selectDistinct().from(users).orderBy(users.id, users.name);

await db.selectDistinct({ id: users.id }).from(users).orderBy(users.id);
```
```sql
select distinct [id], [name] from [users] order by [id], [name];

select distinct [id] from [users] order by [id];
```
</Section>

### Advanced select
Powered by TypeScript, Drizzle APIs let you build your select queries in a variety of flexible ways.

Sneak peek of advanced partial select, for more detailed advanced usage examples - see our [dedicated guide](/docs/mssql/guides/include-or-exclude-columns).

<CodeTabs items={["example 1", "example 2", "example 3", "example 4"]}>
```ts
import { getColumns, sql } from 'drizzle-orm';

await db.select({
    ...getColumns(posts),
    titleLength: sql<number>`length(${posts.title})`,
  }).from(posts);
```
```ts
import { getColumns } from 'drizzle-orm';

const { content, ...rest } = getColumns(posts); // exclude "content" column
await db.select({ ...rest }).from(posts); // select all other columns
```
```ts
await db._query.posts.findMany({
  columns: {
    title: true,
  },
});
```
```ts
await db._query.posts.findMany({
  columns: {
    content: false,
  },
});
```
</CodeTabs>

## ---

### Filters

You can filter the query results using the [filter operators](/docs/mssql/operators) in the `.where()` method:

<Section>
```typescript copy
import { eq, lt, gte, ne } from 'drizzle-orm';

await db.select().from(users).where(eq(users.id, 42));
await db.select().from(users).where(lt(users.id, 42));
await db.select().from(users).where(gte(users.id, 42));
await db.select().from(users).where(ne(users.id, 42));
...
```
```sql
select [id], [name], [age] from [users] where [users].[id] = 42;
select [id], [name], [age] from [users] where [users].[id] < 42;
select [id], [name], [age] from [users] where [users].[id] >= 42;
select [id], [name], [age] from [users] where [users].[id] <> 42;
```
</Section>

All filter operators are implemented using the [`sql`](/docs/mssql/sql) function.
You can use it yourself to write arbitrary SQL filters, or build your own operators.
For inspiration, you can check how the operators provided by Drizzle are [implemented](https://github.com/drizzle-team/drizzle-orm/blob/main/drizzle-orm/src/sql/expressions/conditions.ts).
<Section>
```typescript copy
import { sql } from 'drizzle-orm';
import type { MsSqlColumn } from 'drizzle-orm/mssql-core';

function equals42(col: MsSqlColumn) {
  return sql`${col} = 42`;
}

await db.select().from(users).where(sql`${users.id} < 42`);
await db.select().from(users).where(sql`${users.id} = 42`);
await db.select().from(users).where(equals42(users.id));
await db.select().from(users).where(sql`${users.id} >= 42`);
await db.select().from(users).where(sql`${users.id} <> 42`);
await db.select().from(users).where(sql`lower(${users.name}) = 'aaron'`);
```
```sql
select [id], [name], [age] from [users] where [users].[id] < 42;
select [id], [name], [age] from [users] where [users].[id] = 42;
select [id], [name], [age] from [users] where [users].[id] = 42;
select [id], [name], [age] from [users] where [users].[id] >= 42;
select [id], [name], [age] from [users] where [users].[id] <> 42;
select [id], [name], [age] from [users] where lower([users].[name]) = 'aaron';
```
</Section>

<Callout type='info'>
All the values provided to filter operators and to the `sql` function are parameterized automatically.
For example, this query:
```ts
await db.select().from(users).where(eq(users.id, 42));
```
will be translated to:
```sql
select [id], [name], [age] from [users] where [users].[id] = @par0; -- params: [42]
```
</Callout>

Inverting condition with a `not` operator:
<Section>
```typescript copy
import { eq, not, sql } from 'drizzle-orm';

await db.select().from(users).where(not(eq(users.id, 42)));
await db.select().from(users).where(sql`not ${users.id} = 42`);
```
```sql
select [id], [name], [age] from [users] where not ([users].[id] = 42);
select [id], [name], [age] from [users] where not [users].[id] = 42;
```
</Section>

<Callout type="info">
You can safely alter schema, rename tables and columns
and it will be automatically reflected in your queries because of template interpolation,
as opposed to hardcoding column or table names when writing raw SQL.
</Callout>

### Combining filters
You can logically combine filter operators with `and()` and `or()` operators:
<Section>
```typescript copy
import { eq, and, sql } from 'drizzle-orm';

await db.select().from(users).where(
  and(
    eq(users.id, 42),
    eq(users.name, 'Dan')
  )
);
await db.select().from(users).where(sql`${users.id} = 42 and ${users.name} = 'Dan'`);
```
```sql
select [id], [name], [age] from [users] where (([users].[id] = 42) and ([users].[name] = 'Dan'));
select [id], [name], [age] from [users] where [users].[id] = 42 and [users].[name] = 'Dan';
```
</Section>

<Section>
```typescript copy
import { eq, or, sql } from 'drizzle-orm';

await db.select().from(users).where(
  or(
    eq(users.id, 42), 
    eq(users.name, 'Dan')
  )
);
await db.select().from(users).where(sql`${users.id} = 42 or ${users.name} = 'Dan'`);
```
```sql
select [id], [name], [age] from [users] where (([users].[id] = 42) or ([users].[name] = 'Dan'));
select [id], [name], [age] from [users] where [users].[id] = 42 or [users].[name] = 'Dan';
```
</Section>

### Advanced filters
In combination with TypeScript, Drizzle APIs provide you powerful and flexible ways to combine filters in queries.

Sneak peek of conditional filtering, for more detailed advanced usage examples - see our [dedicated guide](/docs/mssql/guides/conditional-filters-in-query).
<CodeTabs items={["example 1", "example 2"]}>
```ts
const searchPosts = async (term?: string) => {
  await db
    .select()
    .from(posts)
    .where(term ? like(posts.title, term) : undefined);
};
await searchPosts();
await searchPosts('AI');
```
```ts
const searchPosts = async (filters: SQL[]) => {
  await db
    .select()
    .from(posts)
    .where(and(...filters));
};
const filters: SQL[] = [];
filters.push(like(posts.title, 'AI'));
filters.push(inArray(posts.category, ['Tech', 'Art', 'Science']));
filters.push(gt(posts.views, 200));
await searchPosts(filters);
```
</CodeTabs>

## ---

### Fetch & offset

In MSSQL, `FETCH` and `OFFSET` are part of the `ORDER BY` clause, so they can only be used after the `.orderBy()` function

```ts
await db.select().from(users).orderBy(asc(users.id)).offset(5);
await db.select().from(users).orderBy(asc(users.id)).offset(5).fetch(10);
```
```sql
select [id], [name], [age] from [users] offset 5 rows;
select [id], [name], [age] from [users] offset 5 rows fetch next 10 rows;
```

### Top

Limits the rows returned in a query result set to a specified number of rows

```ts
await db.select().top(10).from(users);
```
```sql
select top (10) [id], [name], [age] from [users];
```

### Order By
Use `.orderBy()` to add `order by` clause to the query, sorting the results by the specified fields:
<Section>
```typescript
import { asc, desc } from 'drizzle-orm';

await db.select().from(users).orderBy(users.name);
await db.select().from(users).orderBy(desc(users.name));

// order by multiple fields
await db.select().from(users).orderBy(users.name, users.name2);
await db.select().from(users).orderBy(asc(users.name), desc(users.name2));
```
```sql
select [id], [name], [name2], [age] from [users] order by [users].[name];
select [id], [name], [name2], [age] from [users] order by [users].[name] desc;

select [id], [name], [name2], [age] from [users] order by [users].[name], [users].[name];
select [id], [name], [name2], [age] from [users] order by [users].[name] asc, [users].[name2] desc;
```
</Section>

### Advanced pagination
Powered by TypeScript, Drizzle APIs let you implement all possible SQL pagination and sorting approaches.

Sneak peek of advanced pagination, for more detailed advanced
usage examples - see our dedicated [limit offset pagination](/docs/mssql/guides/limit-offset-pagination)
and [cursor pagination](/docs/mssql/guides/cursor-based-pagination) guides.

<CodeTabs items={["example 1", "example 2", "example 3", "example 4"]}>
```ts
await db
  .select()
  .from(users)
  .orderBy(asc(users.id)) // order by is mandatory
  .offset(4) // the number of rows to skip
  .fetch(4) // the number of rows to fetch
```
```ts
const getUsers = async (page = 1, pageSize = 3) => {
  return await db._query.users.findMany({
    orderBy: (users, { asc }) => asc(users.id),
    limit: pageSize,
    offset: (page - 1) * pageSize,
  });
};
await getUsers();
```
```ts
const getUsers = async (page = 1, pageSize = 10) => {
   const sq = db
    .select({ id: users.id })
    .from(users)
    .orderBy(asc(users.id)) // order by is mandatory
    .offset(pageSize) // the number of rows to skip
    .fetch((page - 1) * pageSize) // the number of rows to fetch
    .as('subquery');
   return await db.select().from(users).innerJoin(sq, eq(users.id, sq.id)).orderBy(users.id);
};
```
```ts
const nextUserPage = async (cursor?: number, pageSize = 3) => {
  return await db
    .select()
	.top(pageSize)
    .from(users)
    .where(cursor ? gt(users.id, cursor) : undefined) // if cursor is provided, get rows after it
    .orderBy(asc(users.id)); // ordering
};
// pass the cursor of the last row of the previous page (id)
await nextUserPage(3);
```
</CodeTabs>

## ---

### WITH clause

Using the `with` clause can help you simplify complex queries by splitting them into smaller subqueries called common table expressions (CTEs):
<Section>
```typescript copy
const sq = db.$with('sq').as(db.select().from(users).where(eq(users.id, 42)));

const result = await db.with(sq).select().from(sq);
```
```sql
with [sq] as (select [id], [name], [age] from [users] where [users].[id] = 42)
select [id], [name], [age] from [sq];
```
</Section>


To select arbitrary SQL values as fields in a CTE and reference them in other CTEs or in the main query,
you need to add aliases to them:
```typescript copy

const sq = db.$with('sq').as(db.select({ 
  name: sql<string>`upper(${users.name})`.as('name'),
})
.from(users));

const result = await db.with(sq).select({ name: sq.name }).from(sq);
```
If you don't provide an alias, the field type will become `DrizzleTypeError` and you won't be able to reference it in other queries.
If you ignore the type error and still try to use the field,
you will get a runtime error, since there's no way to reference that field without an alias.

### Select from subquery
Just like in SQL, you can embed queries into other queries by using the subquery API:
<Section>
```typescript copy
const sq = db.select().from(users).where(eq(users.id, 42)).as('sq');
const result = await db.select().from(sq);
```
```sql
select [id], [name], [age] from (select [id], [name], [age] from [users] where [users].[id] = 42) [sq];
```
</Section>

Subqueries can be used in any place where a table can be used, for example in joins:
<Section>
```typescript copy
const sq = db.select().from(users).where(eq(users.id, 42)).as('sq');
const result = await db.select().from(users).leftJoin(sq, eq(users.id, sq.id));
```
```sql
select [users].[id], [users].[name], [users].[age], [sq].[id], [sq].[name], [sq].[age] from [users]
  left join (select [id], [name], [age] from [users] where [users].[id] = 42) [sq]
    on [users].[id] = [sq].[id];
```
</Section>

## ---

### Aggregations
With Drizzle, you can do aggregations using functions like `sum`, `count`, `avg`, etc. by
grouping and filtering with `.groupBy()` and `.having()` respectfully, same as you would do in raw SQL:

<Section>
```typescript
import { gt, sql } from "drizzle-orm";

await db.select({
  age: users.age,
  count: sql<number>`cast(count(${users.id}) as int)`,
})
  .from(users)
  .groupBy(users.age);

await db.select({
  age: users.age,
  count: sql<number>`cast(count(${users.id}) as int)`,
})
  .from(users)
  .groupBy(users.age)
  .having(({ count }) => gt(count, 1));
```
```sql
select [age], cast(count([id]) as int)
  from [users]
  group by [users].[age];

select [age], cast(count([id]) as int)
  from [users]
  group by [users].[age]
  having cast(count([users].[id]) as int) > 1;
```
</Section>

<Callout type="info">
As an alternative to `cast(... as int)`, you can use [`.mapWith(Number)`](/docs/mssql/sql#sqlmapwith) to cast the value to a number at runtime.

If you need count aggregation - we recommend using our [$count](/docs/mssql/select#count) API
</Callout>

### Aggregations helpers

Drizzle has a set of wrapped `sql` functions, so you don't need to write
`sql` templates for common cases in your app

<Callout type="info">
 Remember, aggregation functions are often used with the GROUP BY clause of the SELECT statement. 
 So if you are selecting using aggregating functions and other columns in one query, 
 be sure to use the `.groupBy` clause
</Callout>

**count**

Returns the number of values in `expression`.
<Section>
```ts
import { count } from 'drizzle-orm'

await db.select({ value: count() }).from(users);
await db.select({ value: count(users.id) }).from(users);
```
```sql
select count(*) from [users];
select count([id]) from [users];
```
```ts
// It's equivalent to writing
await db.select({ 
  value: sql`count(*)`.mapWith(Number) 
}).from(users);

await db.select({ 
  value: sql`count(${users.id})`.mapWith(Number) 
}).from(users);
```
</Section>

**countDistinct**

Returns the number of non-duplicate values in `expression`.
<Section>
```ts
import { countDistinct } from 'drizzle-orm'

await db.select({ value: countDistinct(users.id) }).from(users);
```
```sql
select count(distinct [id]) from [users];
```
```ts
// It's equivalent to writing
await db.select({ 
  value: sql`count(distinct ${users.id})`.mapWith(Number) 
}).from(users);
```
</Section>

**avg**

Returns the average (arithmetic mean) of all non-null values in `expression`.
<Section>
```ts
import { avg } from 'drizzle-orm'

await db.select({ value: avg(users.id) }).from(users);
```
```sql
select avg([id]) from [users];
```
```ts
// It's equivalent to writing
await db.select({ 
  value: sql`avg(${users.id})`.mapWith(String) 
}).from(users);
```
</Section>

**avgDistinct**

Returns the average (arithmetic mean) of all non-null values in `expression`.
<Section>
```ts
import { avgDistinct } from 'drizzle-orm'

await db.select({ value: avgDistinct(users.id) }).from(users);
```
```sql
select avg(distinct [id]) from [users];
```
```ts
// It's equivalent to writing
await db.select({ 
  value: sql`avg(distinct ${users.id})`.mapWith(String) 
}).from(users);
```
</Section>

**sum**

Returns the sum of all non-null values in `expression`.
<Section>
```ts
import { sum } from 'drizzle-orm'

await db.select({ value: sum(users.id) }).from(users);
```
```sql
select sum([id]) from [users];
```
```ts
// It's equivalent to writing
await db.select({ 
  value: sql`sum(${users.id})`.mapWith(String) 
}).from(users);
```
</Section>

**sumDistinct**

Returns the sum of all non-null and non-duplicate values in `expression`.
<Section>
```ts
import { sumDistinct } from 'drizzle-orm'

await db.select({ value: sumDistinct(users.id) }).from(users);
```
```sql
select sum(distinct [id]) from [users];
```
```ts
// It's equivalent to writing
await db.select({ 
  value: sql`sum(distinct ${users.id})`.mapWith(String) 
}).from(users);
```
</Section>

**max**

Returns the maximum value in `expression`.
<Section>
```ts
import { max } from 'drizzle-orm'

await db.select({ value: max(users.id) }).from(users);
```
```sql
select max([id]) from [users];
```
```ts
// It's equivalent to writing
await db.select({ 
  value: sql`max(${expression})`.mapWith(users.id) 
}).from(users);
```
</Section>

**min**

Returns the minimum value in `expression`.
<Section>
```ts
import { min } from 'drizzle-orm'

await db.select({ value: min(users.id) }).from(users);
```
```sql
select min([id]) from [users];
```
```ts
// It's equivalent to writing
await db.select({ 
  value: sql`min(${users.id})`.mapWith(users.id) 
}).from(users);
```
</Section>

A more advanced example:

```typescript copy
const orders = mssqlTable('order', {
  id: int('id').primaryKey(),
  orderDate: datetime2('order_date').notNull(),
  requiredDate: datetime2('required_date').notNull(),
  shippedDate: datetime2('shipped_date'),
  shipVia: int('ship_via').notNull(),
  freight: numeric('freight').notNull(),
  shipName: nvarchar('ship_name', { length: 256 }).notNull(),
  shipCity: nvarchar('ship_city', { length: 256 }).notNull(),
  shipRegion: nvarchar('ship_region', { length: 256 }),
  shipPostalCode: nvarchar('ship_postal_code', { length: 256 }),
  shipCountry: nvarchar('ship_country', { length: 256 }).notNull(),
  customerId: nvarchar('customer_id', { length: 256 }).notNull(),
  employeeId: int('employee_id').notNull(),
});

const details = mssqlTable('order_detail', {
  unitPrice: numeric('unit_price').notNull(),
  quantity: int('quantity').notNull(),
  discount: numeric('discount').notNull(),
  orderId: int('order_id').notNull(),
  productId: int('product_id').notNull(),
});
await db.select({
  id: orders.id,
  shippedDate: orders.shippedDate,
  shipName: orders.shipName,
  shipCity: orders.shipCity,
  shipCountry: orders.shipCountry,
  productsCount: sql<number>`cast(count(${details.productId}) as int)`,
  quantitySum: sql<number>`sum(${details.quantity})`,
  totalPrice: sql<number>`sum(${details.quantity} * ${details.unitPrice})`,
})
  .from(orders)
  .leftJoin(details, eq(orders.id, details.orderId))
  .groupBy(
    orders.id,
    orders.shipName,
    orders.shippedDate,
    orders.shipCity,
    orders.shipCountry,
  )
  .orderBy(asc(orders.id));
```

### $count

Currently not supported

## ---

### Iterator

If you need to return a very large amount of rows from a query and you don't want to load them all into memory, you can use `.iterator()` to convert the query into an async iterator:

```ts copy
const iterator = db.select().from(users).iterator();

for await (const row of iterator) {
  console.log(row);
}
```

It also works with prepared statements:

```ts copy
const query = db.select().from(users).prepare();
const iterator = query.iterator();

for await (const row of iterator) {
  console.log(row);
}
```

Source: https://orm.drizzle.team/docs/mssql/set-operations

import CodeTabs from '@mdx/CodeTabs.astro';
import CodeTab from '@mdx/CodeTab.astro';
import Callout from '@mdx/Callout.astro';

# Set Operations

SQL set operations combine the results of multiple query blocks into a single result. 
The SQL standard defines the following three set operations: `UNION`, `INTERSECT`, `EXCEPT`, `UNION ALL`.

### Union
Combine all results from two query blocks into a single result, omitting any duplicates.

Get all names from customers and users tables without duplicates.

<CodeTabs items={["import-pattern", "builder-pattern", "schema.ts"]}>
	<CodeTab>
	```typescript copy
    import { union } from 'drizzle-orm/mssql-core'
    import { users, customers } from './schema'

    const allNamesForUserQuery = db.select({ name: users.name }).from(users);

    const result = await union(
		allNamesForUserQuery,
		db.select({ name: customers.name }).from(customers)
	);
    ```
    ```sql
    (select [name] from [sellers])
    union
    (select [name] from [customers])
    ```
	</CodeTab>
    <CodeTab>
    ```ts copy
    import { users, customers } from './schema'

    const result = await db
      .select({ name: users.name })
      .from(users)
      .union(db.select({ name: customers.name }).from(customers));
    ```
    ```sql
    (select [name] from [sellers])
    union
    (select [name] from [customers])
    ```
    </CodeTab>
    <CodeTab>
	```typescript copy
    import { int, mssqlTable, text, varchar } from "drizzle-orm/mssql-core";

    export const users = mssqlTable('sellers', {
        id: int().primaryKey(),
        name: varchar({ length: 256 }).notNull(),
        address: text(),
    });
    
    export const customers = mssqlTable('customers', {
        id: int().primaryKey(),
        name: varchar({ length: 256 }).notNull(),
        city: text(),
        email: varchar({ length: 256 }).notNull()
    });
    ```
    </CodeTab>
  </CodeTabs>

### Union All
Combine all results from two query blocks into a single result, with duplicates.

Let's consider a scenario where you have two tables, one representing online sales and the other 
representing in-store sales. In this case, you want to combine the data from both tables into a
single result set. Since there might be duplicate transactions, 
you want to keep all the records and not eliminate duplicates.

<CodeTabs items={["import-pattern", "builder-pattern", "schema.ts"]}>
	<CodeTab>
	```typescript copy
    import { unionAll } from 'drizzle-orm/mssql-core'
    import { onlineSales, inStoreSales } from './schema'

    const onlineTransactions = db.select({ transaction: onlineSales.transactionId }).from(onlineSales);
    const inStoreTransactions = db.select({ transaction: inStoreSales.transactionId }).from(inStoreSales);

    const result = await unionAll(onlineTransactions, inStoreTransactions);
    ```
    ```sql
    (select [transaction_id] from [online_sales])
    union all
    (select [transaction_id] from [in_store_sales])
    ```
    </CodeTab>
    <CodeTab>
    ```ts copy
    import { onlineSales, inStoreSales } from './schema'

    const result = await db
      .select({ transaction: onlineSales.transactionId })
      .from(onlineSales)
      .unionAll(
        db.select({ transaction: inStoreSales.transactionId }).from(inStoreSales)
      );
    ```
    ```sql
    (select [transaction_id] from [online_sales])
    union all 
    (select [transaction_id] from [in_store_sales])
    ```
	</CodeTab>
    <CodeTab>
	```typescript copy
    import { int, mssqlTable, text, datetime2, varchar } from "drizzle-orm/mssql-core";

    export const onlineSales = mssqlTable('online_sales', {
        transactionId: int('transaction_id').primaryKey(),
        productId: int('product_id').unique(),
        quantitySold: int('quantity_sold'),
        saleDate: datetime2('sale_date', { mode: 'date' }),
    });
    
    export const inStoreSales = mssqlTable('in_store_sales', {
        transactionId: int('transaction_id').primaryKey(),
        productId: int('product_id').unique(),
        quantitySold: int('quantity_sold'),
        saleDate: datetime2('sale_date', { mode: 'date' }),
    });
    ```
    </CodeTab>
  </CodeTabs>

### Intersect
Combine only those rows which the results of two query blocks have in common, omitting any duplicates.

Suppose you have two tables that store information about students' course enrollments. 
You want to find the courses that are common between two different departments,
but you want distinct course names, and you're not interested in counting multiple 
enrollments of the same course by the same student.

In this scenario, you want to find courses that are common between the two departments but don't want 
to count the same course multiple times even if multiple students from the same department are enrolled in it.

<CodeTabs items={["import-pattern", "builder-pattern", "schema.ts"]}>
	<CodeTab>
	```typescript copy
    import { intersect } from 'drizzle-orm/mssql-core'
    import { depA, depB } from './schema'

    const departmentACourses = db.select({ courseName: depA.courseName }).from(depA);
    const departmentBCourses = db.select({ courseName: depB.courseName }).from(depB);

    const result = await intersect(departmentACourses, departmentBCourses);
    ```
    ```sql
    (select [projects_name] from [department_a_projects])
    intersect
    (select [projects_name] from [department_b_projects])
    ```
	</CodeTab>
    <CodeTab>
    ```typescript copy
    import { depA, depB } from './schema'

    const result = await db
      .select({ courseName: depA.courseName })
      .from(depA)
      .intersect(db.select({ courseName: depB.courseName }).from(depB));
    ```
    ```sql
    (select [projects_name] from [department_a_projects])
    intersect
    (select [projects_name] from [department_b_projects])
    ```
    </CodeTab>
    <CodeTab>
	```typescript copy
    import { int, mssqlTable, varchar } from "drizzle-orm/mssql-core";

    export const depA = mssqlTable('department_a_courses', {
        studentId: int('student_id'),
        courseName: varchar('course_name', { length: 256 }).notNull(),
    });
    
    export const depB = mssqlTable('department_b_courses', {
        studentId: int('student_id'),
        courseName: varchar('course_name', { length: 256 }).notNull(),
    });
    ```
    </CodeTab>
  </CodeTabs>

### Except
For two query blocks A and B, return all results from A which are not also present in B, omitting any duplicates.

Suppose you have two tables that store information about employees' project assignments. 
You want to find the projects that are unique to one department 
and not shared with another department, excluding duplicates.

In this scenario, you want to identify the projects that are exclusive to one department and
not shared with the other department. You don't want to count the same project 
multiple times, even if multiple employees from the same department are assigned to it.

<CodeTabs items={["import-pattern", "builder-pattern", "schema.ts"]}>
	<CodeTab>
	```typescript copy
    import { except } from 'drizzle-orm/mssql-core'
    import { depA, depB } from './schema'

    const departmentACourses = db.select({ courseName: depA.projectsName }).from(depA);
    const departmentBCourses = db.select({ courseName: depB.projectsName }).from(depB);

    const result = await except(departmentACourses, departmentBCourses);
    ```
    ```sql
    (select [projects_name] from [department_a_projects])
    except
    (select [projects_name] from [department_b_projects])
    ```
	</CodeTab>
    <CodeTab>
    ```ts copy
    import { depA, depB } from './schema'

    const result = await db
        .select({ courseName: depA.projectsName })
        .from(depA)
        .except(db.select({ courseName: depB.projectsName }).from(depB));
    ```
    ```sql
    (select [projects_name] from [department_a_projects])
    except
    (select [projects_name] from [department_b_projects])
    ```
    </CodeTab>
    <CodeTab>
	```typescript 
    import { int, mssqlTable, varchar } from "drizzle-orm/mssql-core";

    export const depA = mssqlTable('department_a_projects', {
        employeeId: int('employee_id'),
        projectsName: varchar('projects_name', { length: 256 }).notNull(),
    });
    
    export const depB = mssqlTable('department_b_projects', {
        employeeId: int('employee_id'),
        projectsName: varchar('projects_name', { length: 256 }).notNull(),
    });
    ```
    </CodeTab>
  </CodeTabs>

Source: https://orm.drizzle.team/docs/mssql/sql-schema-declaration

import Callout from '@mdx/Callout.astro';
import SimpleLinkCards from '@mdx/SimpleLinkCards.astro';
import CodeTabs from "@mdx/CodeTabs.astro";
import Section from '@mdx/Section.astro';
import Flex from "@mdx/Flex.astro"
import LinksList from "@mdx/LinksList.astro"

# Drizzle schema

Drizzle lets you define a schema in TypeScript with various models and properties supported by the underlying database. 
When you define your schema, it serves as the source of truth for future modifications in queries (using Drizzle-ORM)
and migrations (using Drizzle-Kit).

<Callout> 
If you are using Drizzle-Kit for the migration process, make sure to export all the models defined in your schema files so that Drizzle-Kit can import them and use them in the migration diff process. 
</Callout>

<CodeTabs items={["Using imports", "Using callback", "Using import *"]}>
```ts
import { int, mssqlTable, varchar } from "drizzle-orm/mssql-core";

export const usersTable = mssqlTable("users", {
  id: int().primaryKey().identity(),
  name: varchar({ length: 256 }).notNull(),
  age: int().notNull(),
  email: varchar({ length: 256 }).notNull().unique(),
});
```
```ts
import { mssqlTable } from "drizzle-orm/mssql-core";

export const usersTable = mssqlTable("users", (t) => ({
  id: t.int().primaryKey().identity(),
  name: t.varchar({ length: 256 }).notNull(),
  age: t.int().notNull(),
  email: t.varchar({ length: 256 }).notNull().unique(),
}));
```
```ts
import * as t from "drizzle-orm/mssql-core";

export const usersTable = t.mssqlTable("users", {
  id: t.int().primaryKey().identity(),
  name: t.varchar({ length: 256 }).notNull(),
  age: t.int().notNull(),
  email: t.varchar({ length: 256 }).notNull().unique(),
});
```
</CodeTabs>

## Organize your schema files 
You can declare your SQL schema directly in TypeScript either in a single `schema.ts` file,
or you can spread them around — whichever you prefer, all the freedom!

#### Schema in 1 file
The most common way to declare your schema with Drizzle is to put all your tables into one `schema.ts` file.

> Note: You can name your schema file whatever you like. For example, it could be `models.ts`, or something else.

This approach works well if you don't have too many table models defined, or if you're okay with keeping them all in one file

Example:
```plaintext
📦 <project root>
 └ 📂 src
    └ 📂 db
       └ 📜 schema.ts
```

In the `drizzle.config.ts` file, you need to specify the path to your schema file. With this configuration, Drizzle will 
read from the `schema.ts` file and use this information during the migration generation process. For more information 
about the `drizzle.config.ts` file and migrations with Drizzle, please check: [link](/docs/mssql/drizzle-config-file)
```ts
import { defineConfig } from "drizzle-kit";

export default defineConfig({
  dialect: 'mssql',
  schema: './src/db/schema.ts'
})
```

#### Schema in multiple files

You can place your Drizzle models — such as tables, enums, sequences, etc. — not only in one file but in any file you prefer. 
The only thing you must ensure is that you export all the models from those files so that the Drizzle kit can import 
them and use them in migrations.

One use case would be to separate each table into its own file.
```plaintext
📦 <project root>
 └ 📂 src
    └ 📂 db
       └ 📂 schema
          ├ 📜 users.ts
          ├ 📜 countries.ts
          ├ 📜 cities.ts
          ├ 📜 products.ts
          ├ 📜 clients.ts
          └ 📜 etc.ts
```

In the `drizzle.config.ts` file, you need to specify the path to your schema folder. With this configuration, Drizzle will 
read from the `schema` folder and find all the files recursively and get all the drizzle tables from there. For more information 
about the `drizzle.config.ts` file and migrations with Drizzle, please check: [link](/docs/mssql/drizzle-config-file)

```ts
import { defineConfig } from "drizzle-kit";

export default defineConfig({
  dialect: 'mssql',
  schema: './src/db/schema'
})
```

You can also group them in any way you like, such as creating groups for user-related tables, messaging-related tables, product-related tables, etc. 
```plaintext
📦 <project root>
 └ 📂 src
    └ 📂 db
       └ 📂 schema
          ├ 📜 users.ts
          ├ 📜 messaging.ts
          └ 📜 products.ts
```

## Shape your data schema

Drizzle schema consists of several model types from database you are using. With drizzle you can specify:
- Tables with columns, constraints, etc.
- Schemas
- Views
- etc.

Let's go one by one and check how the schema should be defined with drizzle

#### **Tables and columns declaration** 

A table in Drizzle should be defined with at least 1 column, the same as it should be done in database. There is one important thing to know,
there is no such thing as a common table object in Drizzle. You need to choose the MSSQL table object.

![](@/assets/images/table-structure.svg)

```ts copy
import { mssqlTable, int } from "drizzle-orm/mssql-core"

export const users = mssqlTable('users', {
  id: int()
});
```

By default, Drizzle will use the TypeScript key names for columns in database queries. 
Therefore, the schema and query from the example will generate the SQL query shown below

<Callout>
This example uses a db object, whose initialization is not covered in this part of the documentation. To learn how to connect to the database, please refer to the [Connections Docs](/docs/mssql/get-started-mssql)
</Callout>

\
**TypeScript key = database key**
<Section>
```ts
// schema.ts
import { int, mssqlTable, varchar } from "drizzle-orm/mssql-core";

export const users = mssqlTable('users', {
  id: int(),
  first_name: varchar({ length: 256 })
})
```
```ts
// query.ts
await db.select().from(users);
```
```sql
SELECT [id], [first_name] FROM [users];
```
</Section>

If you want to use different names in your TypeScript code and in the database, you can use column aliases

<Section>
```ts
// schema.ts
import { int, mssqlTable, varchar } from "drizzle-orm/mssql-core";

export const users = mssqlTable('users', {
  id: int(),
  firstName: varchar('first_name', { length: 256 })
})
```
```ts
// query.ts
await db.select().from(users);
```
```sql
SELECT [id], [first_name] FROM [users];
```
</Section>

### Camel and Snake casing

Database model names often use `snake_case` conventions, while in TypeScript, it is common to use `camelCase` for naming models.
This can lead to a lot of alias definitions in the schema. To address this, Drizzle provides a way to automatically
map `camelCase` from TypeScript to `snake_case` in the database via a dedicated builder.

Use the `snakeCase` or `camelCase` builder from `drizzle-orm/mssql-core` to declare a table whose column keys are
automatically mapped to the chosen database naming convention

<Section>
```ts {2,4,11,12}
// schema.ts
import { snakeCase, camelCase } from 'drizzle-orm/mssql-core';

export const users = snakeCase.table('users', {
  id: int().primaryKey(),
  fullName: text(), // → full_name in DB
  createdAt: datetime2(), // → created_at in DB
});

// Available on all entity types:
snakeCase.table / snakeCase.view / snakeCase.schema
camelCase.table / camelCase.view / camelCase.schema
```
```ts
// db.ts
import { drizzle } from "drizzle-orm/node-mssql";

const db = drizzle({ connection: process.env.DATABASE_URL })
```
```ts
// query.ts
await db.select().from(users);
```
```sql
select [id], [full_name], [created_at] from [users]
```
</Section>

### Advanced

There are a few tricks you can use with Drizzle ORM. As long as Drizzle is entirely in TypeScript files, 
you can essentially do anything you would in a simple TypeScript project with your code.

One common feature is to separate columns into different places and then reuse them. 
For example, consider the `updated_at`, `created_at`, and `deleted_at` columns. Many tables/models may need these 
three fields to track and analyze the creation, deletion, and updates of entities in a system

We can define those columns in a separate file and then import and spread them across all the table objects you have

<Section>
```ts
// columns.helpers.ts
export const timestamps = {
  updated_at: datetime2(),
  created_at: datetime2()..defaultGetDate().notNull(),
  deleted_at: datetime2(),
}
```
```ts
// users.sql.ts
export const users = mssqlTable('users', {
  id: int(),
  ...timestamps
})
```
```ts
// posts.sql.ts
export const posts = mssqlTable('posts', {
  id: int(),
  ...timestamps
})
```
</Section>

#### **Schemas**

\
In MSSQL, there is an entity called a `schema` (which we believe should be called `folders`). This creates a structure in MSSQL:

![](@/assets/images/postgresql-db-structure.png)

You can manage your PostgreSQL schemas with `mssqlSchema` and place any other models inside it.

Define the schema you want to manage using Drizzle
```ts
import { mssqlSchema } from "drizzle-orm/mssql-core"

export const customSchema = mssqlSchema('custom');
```

Then place the table inside the schema object
```ts {5-7}
import { int, mssqlSchema } from "drizzle-orm/mssql-core";

export const customSchema = mssqlSchema('custom');

export const users = customSchema.table('users', {
  id: int()
})
```

### Example

Once you know the basics, let's define a schema example for a real project to get a better view and understanding

> All examples will use `generateUniqueString`. The implementation for it will be provided after all the schema examples

```ts copy
import type { AnyMsSqlColumn } from "drizzle-orm/mssql-core";
import { mssqlTable as table } from "drizzle-orm/mssql-core";
import * as t from "drizzle-orm/mssql-core";

export const users = table(
  "users",
  {
    id: t.int().primaryKey().identity(),
    firstName: t.varchar("first_name", { length: 256 }),
    lastName: t.varchar("last_name", { length: 256 }),
    email: t.varchar({ length: 256 }).notNull(),
    invitee: t.int().references((): AnyMsSqlColumn => users.id),
    role: t.varchar({ length: 20, enum: ["guest", "admin", "user"] }).default("guest"),
  },
  (table) => [
    t.uniqueIndex("email_idx").on(table.email)
  ]
);

export const posts = table(
  "posts",
  {
    id: t.int().primaryKey().identity(),
    slug: t.varchar({ length: 256 }).$default(() => generateUniqueString(16)),
    title: t.varchar({ length: 256 }),
    ownerId: t.int("owner_id").references(() => users.id),
  },
  (table) => [
    t.uniqueIndex("slug_idx").on(table.slug),
    t.index("title_idx").on(table.title),
  ]
);

export const comments = table("comments", {
  id: t.int().primaryKey().identity(),
  text: t.varchar({ length: 256 }),
  postId: t.int("post_id").references(() => posts.id),
  ownerId: t.int("owner_id").references(() => users.id),
});
```

**`generateUniqueString` implementation:**
```ts
function generateUniqueString(length: number = 12): string {
  const characters =
    "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
  let uniqueString = "";

  for (let i = 0; i < length; i++) {
    const randomIndex = Math.floor(Math.random() * characters.length);
    uniqueString += characters[randomIndex];
  }

  return uniqueString;
}
```

#### What's next?
<br/>
<Flex>
  <LinksList 
    title='Manage schema'
    links={[
        ["Column types", "/docs/mssql/column-types"], 
        ["Indexes and Constraints", "/docs/mssql/indexes-constraints"],
        ["Database Views", "/docs/mssql/views"],
        ["Database Schemas", "/docs/mssql/schemas"],
      ]}
  />
  <LinksList 
    title='Zero to Hero'
    links={[
        ["Database connection", "/docs/mssql/connect-overview"], 
        ["Data querying", "/docs/mssql/data-querying"], 
        ["Migrations", "/docs/mssql/migrations"], 
      ]}
  />
</Flex>


Source: https://orm.drizzle.team/docs/mssql/sql

import Callout from '@mdx/Callout.astro';
import Section from '@mdx/Section.astro';

# Magical `sql` operator 🪄

When working with an ORM library, there may be cases where you find it challenging to write a
specific query using the provided ORM syntax. In such situations, you can resort to using
raw queries, which involve constructing a query as a raw string. However, raw queries often
lack the benefits of type safety and query parameterization.

To address this, many libraries have introduced the concept of an `sql` template. This template 
allows you to write more type-safe and parameterized queries, enhancing the overall safety and 
flexibility of your code. Drizzle, being a powerful ORM library, also supports the sql template.

With Drizzle's `sql` template, you can go even further in crafting queries. If you encounter 
difficulties in writing an entire query using the library's query builder, you can selectively
use the `sql` template within specific sections of the Drizzle query. This flexibility enables you 
to employ the sql template in partial SELECT statements, WHERE clauses, ORDER BY clauses, HAVING
clauses, GROUP BY clauses, and even in relational query builders.

By leveraging the capabilities of the sql template in Drizzle, you can maintain the advantages 
of type safety and query parameterization while achieving the desired query structure and complexity.
This empowers you to create more robust and maintainable code within your application.

## sql`` template

One of the most common usages you may encounter in other ORMs as well 
is the ability to use `sql` queries as-is for raw queries.

```typescript copy
import { sql } from 'drizzle-orm' 

const id = 69;
await db.execute(sql`select * from ${usersTable} where ${usersTable.id} = ${id}`)
```

It will generate the current query

```sql
select * from [users] where [users].[id] = @par0 -- params: [69]
```

Any tables and columns provided to the sql parameter are automatically mapped to their corresponding SQL 
syntax with escaped names for tables, and the escaped table names are appended to column names. 

Additionally, any dynamic parameters such as `${id}` will be mapped to the @par0 placeholder, 
and the corresponding values will be moved to an array of values that are passed separately to the database. 

This approach effectively prevents any potential SQL Injection vulnerabilities.

## `sql<T>`

<Callout type="info" emoji="ℹ️">
    Please note that `sql<T>` does not perform any runtime mapping. The type you define using `sql<T>` is
    purely a helper for Drizzle. It is important to understand that there is no feasible way to 
    determine the exact type dynamically, as SQL queries can be highly versatile and customizable. 
</Callout>

You can define a custom type in Drizzle to be used in places where fields require a specific type other than `unknown`.

This feature is particularly useful in partial select queries, ensuring consistent typing for selected fields:

```typescript
// without sql<T> type defined
const response: { lowerName: unknown }[] = await db.select({
    lowerName: sql`lower(${usersTable.id})`
}).from(usersTable);

// with sql<T> type defined
const response: { lowerName: string }[] = await db.select({
    lowerName: sql<string>`lower(${usersTable.id})`
}).from(usersTable);
```

## `sql``.mapWith()`

For the cases you need to make a runtime mapping for values passed from database driver to drizzle you can use `.mapWith()`

This function accepts different values, that will map response in runtime.

You can replicate a specific column mapping strategy as long as
the interface inside mapWith is the same interface that is implemented by Column.

```typescript
import { mssqlTable, int, text } from 'drizzle-orm/mssql-core';

const usersTable = mssqlTable('users', {
    id: int().primaryKey().identity(),
    name: text().notNull(),
});

//  at runtime this values will be mapped same as `text` column is mapped in drizzle
sql`...`.mapWith(usersTable.name);
```

You can also pass your own implementation for the `DriverValueDecoder` interface:

```ts 
sql``.mapWith({
	mapFromDriverValue: (value: any) => {
		const mappedValue = value;
		// mapping you want to apply
		return mappedValue;
	},
});
    
// or
sql``.mapWith(Number);
```

## `sql``.as<T>()`

In different cases, it can sometimes be challenging to determine how to name a custom field that you want to use.
You may encounter situations where you need to explicitly specify an alias for a 
field that will be selected. This can be particularly useful when dealing with complex queries. 

To address these scenarios, we have introduced a helpful `.as('alias_name')` helper, which allows 
you to define an alias explicitly. By utilizing this feature, you can provide a clear and meaningful 
name for the field, making your queries more intuitive and readable.

<Section>
```typescript
sql`lower(${usersTable.name})`.as('lower_name')
```
```sql
... [users].[name] as [lower_name] ...
```
</Section>

## `sql.raw()`

There are cases where you may not need to create parameterized values from input or map tables/columns to escaped ones. 
Instead, you might simply want to generate queries as they are. For such situations, we provide the `sql.raw()` function.

The `sql.raw()` function allows you to include raw SQL statements within your queries without any additional processing or escaping.
This can be useful when you have pre-constructed SQL statements or when you need to incorporate complex or dynamic 
SQL code directly into your queries.

<Section>
```typescript
sql.raw(`select * from users where id = ${12}`);
// vs
sql`select * from users where id = ${12}`;
```
```sql
select * from users where id = 12;
--> vs
select * from users where id = @par0; --> [12]
```
</Section>

You can also utilize `sql.raw()` within the sql function, enabling you to include any raw string
without escaping it through the main `sql` template function.

By using `sql.raw()` inside the `sql` function, you can incorporate unescaped raw strings 
directly into your queries. This can be particularly useful when you have specific
SQL code or expressions that should remain untouched by the template function's automatic escaping or modification.

<Section>
```typescript
sql`select * from ${usersTable} where id = ${12}`;
// vs
sql`select * from ${usersTable} where id = ${sql.raw(12)}`;
```
```sql
select * from [users] where id = @par0; --> [12]
--> vs
select * from [users] where id = 12;
```
</Section>

## sql.fromList()

The `sql` template generates sql chunks, which are arrays of SQL parts that will be concatenated 
into the query and params after applying the SQL to the database or query in Drizzle.

In certain scenarios, you may need to aggregate these chunks into an array using custom business 
logic and then concatenate them into a single SQL statement that can be passed to the database or query.
For such cases, the fromList function can be quite useful.

The fromList function allows you to combine multiple SQL chunks into a single SQL statement. 
You can use it to aggregate and concatenate the individual SQL parts according to your specific 
requirements and then obtain a unified SQL query that can be executed.

<Section>
```typescript
const sqlChunks: SQL[] = [];

sqlChunks.push(sql`select * from users`);

// some logic

sqlChunks.push(sql` where `);

// some logic

for (let i = 0; i < 5; i++) {
	sqlChunks.push(sql`id = ${i}`);

	if (i === 4) continue;
	sqlChunks.push(sql` or `);
}

const finalSql: SQL = sql.fromList(sqlChunks)
```
```sql
select * from users where id = @par0 or id = @par1 or id = @par2 or id = @par3 or id = @par4; --> [0, 1, 2, 3, 4]
```
</Section>

## sql.join()

Indeed, the `sql.join` function serves a similar purpose to the fromList helper. 
However, it provides additional flexibility when it comes to handling spaces between
SQL chunks or specifying custom separators for concatenating the SQL chunks.

With `sql.join`, you can concatenate SQL chunks together using a specified separator. 
This separator can be any string or character that you want to insert between the chunks. 

This is particularly useful when you have specific requirements for formatting or delimiting 
the SQL chunks. By specifying a custom separator, you can achieve the desired structure and formatting 
in the final SQL query.

<Section>
```typescript
const sqlChunks: SQL[] = [];

sqlChunks.push(sql`select * from users`);

// some logic

sqlChunks.push(sql`where`);

// some logic

for (let i = 0; i < 5; i++) {
	sqlChunks.push(sql`id = ${i}`);

if (i === 4) continue;
    sqlChunks.push(sql`or`);
}

const finalSql: SQL = sql.join(sqlChunks, sql.raw(' '));
```
```sql
select * from users where id = @par0 or id = @par1 or id = @par2 or id = @par3 or id = @par4; --> [0, 1, 2, 3, 4]
```
</Section>

## sql.append()

If you have already generated SQL using the `sql` template, you can achieve the same behavior as `fromList`
by using the append function to directly add a new chunk to the generated SQL.

By using the append function, you can dynamically add additional SQL chunks to the existing SQL string,
effectively concatenating them together. This allows you to incorporate custom logic or business 
rules for aggregating the chunks into the final SQL query.

<Section>
```typescript 
const finalSql = sql`select * from users`;

// some logic

finalSql.append(sql` where `);

// some logic

for (let i = 0; i < 5; i++) {
	finalSql.append(sql`id = ${i}`);

	if (i === 4) continue;
	finalSql.append(sql` or `);
}
```
```sql
select * from users where id = @par0 or id = @par1 or id = @par2 or id = @par3 or id = @par4; --> [0, 1, 2, 3, 4]
```
</Section>

## sql.empty()

By using sql.empty(), you can start with a blank SQL object and then dynamically append SQL chunks to it as needed. This allows you to construct the SQL query incrementally, applying custom logic or conditions to determine the contents of each chunk.

Once you have initialized the SQL object using sql.empty(), you can take advantage of the full range
of sql template features such as parameterization, composition, and escaping. 
This empowers you to construct the SQL query in a flexible and controlled manner, 
adapting it to your specific requirements.

```typescript 
const finalSql = sql.empty();

// some logic

finalSql.append(sql`select * from users`);

// some logic

finalSql.append(sql` where `);

// some logic

for (let i = 0; i < 5; i++) {
	finalSql.append(sql`id = ${i}`);

	if (i === 4) continue;
	finalSql.append(sql` or `);
}
```
```sql
select * from users where id = @par0 or id = @par1 or id = @par2 or id = @par3 or id = @par4; --> [0, 1, 2, 3, 4]
```

## Convert `sql` to string and params

In all the previous examples, you observed the usage of SQL template syntax in TypeScript along with 
the generated SQL output.

If you need to obtain the query string and corresponding parameters generated from the SQL template, 
you must specify the database dialect you intend to generate the query for. Different databases have
varying syntax for parameterization and escaping, so selecting the appropriate dialect is crucial.

Once you have chosen the dialect, you can utilize the corresponding implementation's functionality
to convert the SQL template into the desired query string and parameter format. This ensures 
compatibility with the specific database system you are working with.

<Section>
```typescript copy
import { MsSqlDialect } from 'drizzle-orm/mssql-core';

const mssqlDialect = new MsSqlDialect();
mssqlDialect.sqlToQuery(sql`select * from ${usersTable} where ${usersTable.id} = ${12}`);
```
```sql
select * from [users] where [users].[id] = @par0; --> [ 12 ]
```
</Section>

## `sql` select

You can use the sql functionality in partial select queries as well. Partial select queries allow you to 
retrieve specific fields or columns from a table rather than fetching the entire row.

For more detailed information about partial select queries, you can refer to the Core API
documentation available at **[Core API docs](/docs/mssql/select#basic-and-partial-select)**.

**Select different custom fields from table**

Here you can see a usage for **[`sql<T>`](/docs/mssql/sql#sqlt)**, **[`sql``.mapWith()`](/docs/mssql/sql#sqlmapwith)**, **[`sql``.as<T>()`](/docs/mssql/sql#sqlast)**.

<Section>
```typescript copy
import { sql } from 'drizzle-orm'
import { usersTable } from './schema'

await db.select({
    id: usersTable.id,
    lowerName: sql<string>`lower(${usersTable.name})`,
    aliasedName: sql<string>`lower(${usersTable.name})`.as('aliased_column'),
    count: sql<number>`count(*)`.mapWith(Number) 
}).from(usersTable)
```
```sql
select [id], lower([name]), lower([name]) as [aliased_column], count(*) from [users];
```
</Section>

## `sql` in where

Indeed, Drizzle provides a set of available expressions that you can use within the sql template. 
However, it is true that databases often have a wider range of expressions available, 
including those provided through extensions or other means.

To ensure flexibility and enable you to utilize any expressions that are not natively
supported by Drizzle, you have the freedom to write the SQL template
directly using the sql function. This allows you to leverage the full power of
SQL and incorporate any expressions or functionalities specific to your target database.

By using the sql template, you are not restricted to only the predefined expressions in Drizzle. 
Instead, you can express complex queries and incorporate any supported expressions that 
the underlying database system provides.

**Filtering by `id` but with sql**
<Section>
```typescript copy
import { sql } from 'drizzle-orm'
import { usersTable } from './schema'

const id = 77

await db.select()
        .from(usersTable)
        .where(sql`${usersTable.id} = ${id}`)
```
```sql
select * from [users] where [users].[id] = @par0; --> [ 77 ]
```
</Section>

**Advanced fulltext search where statement**
<Section>
```typescript copy
import { sql } from 'drizzle-orm'
import { usersTable } from './schema'

const searchParam = "%Ale%"

await db.select()
        .from(usersTable)
        .where(sql`lower(${usersTable.name}) like lower(${searchPattern})`)
```
```sql
select * from [users] where lower([users].[name]) like lower(@par0); --> [ "%Ale%" ]
```
</Section>

## `sql` in orderBy

The `sql` template can indeed be used in the ORDER BY clause when you need specific functionality for ordering that is not
available in Drizzle, but you prefer not to resort to raw SQL.

<Section>
```typescript copy
import { sql } from 'drizzle-orm'
import { usersTable } from './schema'

await db.select().from(usersTable).orderBy(sql`${usersTable.id} desc`)
```
```sql
select * from [users] order by [users].[id] desc;
```
</Section>

## `sql` in having and groupBy

The `sql` template can indeed be used in the HAVING and GROUP BY clauses when you need specific functionality for ordering that is not
available in Drizzle, but you prefer not to resort to raw SQL.

<Section>
```typescript copy
import { sql } from 'drizzle-orm'
import { usersTable } from './schema'

await db.select({ 
    projectId: usersTable.projectId,
    count: sql<number>`count(${usersTable.id})`.mapWith(Number)
}).from(usersTable)
    .groupBy(sql`${usersTable.projectId}`)
    .having(sql`count(${usersTable.id}) > 300`)
```
```sql
select [project_id], count([id]) from [users] group by [users].[project_id] having count([users].[id]) > 300;
```
</Section>


Source: https://orm.drizzle.team/docs/mssql/transactions

# Transactions

SQL transaction is a grouping of one or more SQL statements that interact with a database.
A transaction in its entirety can commit to a database as a single logical unit
or rollback (become undone) as a single logical unit.

Drizzle ORM provides APIs to run SQL statements in transactions:

```ts copy
const db = drizzle(...)

await db.transaction(async (tx) => {
  await tx.update(accounts).set({ balance: sql`${accounts.balance} - 100.00` }).where(eq(users.name, 'Dan'));
  await tx.update(accounts).set({ balance: sql`${accounts.balance} + 100.00` }).where(eq(users.name, 'Andrew'));
});
```

Drizzle ORM supports `savepoints` with nested transactions API:

```ts copy {7-9}
const db = drizzle(...)

await db.transaction(async (tx) => {
  await tx.update(accounts).set({ balance: sql`${accounts.balance} - 100.00` }).where(eq(users.name, 'Dan'));
  await tx.update(accounts).set({ balance: sql`${accounts.balance} + 100.00` }).where(eq(users.name, 'Andrew'));

  await tx.transaction(async (tx2) => {
    await tx2.update(users).set({ name: "Mr. Dan" }).where(eq(users.name, "Dan"));
  });
});
```

You can embed business logic to the transaction and rollback whenever needed:

```ts copy {7}
const db = drizzle(...)

await db.transaction(async (tx) => {
  const [account] = await tx.select({ balance: accounts.balance }).from(accounts).where(eq(users.name, 'Dan'));
  if (account.balance < 100) {
    // This throws an exception that rollbacks the transaction.
    tx.rollback()
  }

  await tx.update(accounts).set({ balance: sql`${accounts.balance} - 100.00` }).where(eq(users.name, 'Dan'));
  await tx.update(accounts).set({ balance: sql`${accounts.balance} + 100.00` }).where(eq(users.name, 'Andrew'));
});
```

You can return values from the transaction:

```ts copy {8}
const db = drizzle(...)

const newBalance: number = await db.transaction(async (tx) => {
  await tx.update(accounts).set({ balance: sql`${accounts.balance} - 100.00` }).where(eq(users.name, 'Dan'));
  await tx.update(accounts).set({ balance: sql`${accounts.balance} + 100.00` }).where(eq(users.name, 'Andrew'));

  const [account] = await tx.select({ balance: accounts.balance }).from(accounts).where(eq(users.name, 'Dan'));
  return account.balance;
});
```

You can use transactions with **[relational queries](/docs/mssql/rqb)**:

```ts
const db = drizzle({ schema })

await db.transaction(async (tx) => {
  await tx._query.users.findMany({
    with: {
      accounts: true
    }
  });
});
```

We provide dialect-specific transaction configuration APIs:

```ts {6}
await db.transaction(
  async (tx) => {
    await tx.update(accounts).set({ balance: sql`${accounts.balance} - 100.00` }).where(eq(users.name, "Dan"));
    await tx.update(accounts).set({ balance: sql`${accounts.balance} + 100.00` }).where(eq(users.name, "Andrew"));
  }, {
    isolationLevel: "read committed",
  }
);

interface MsSqlTransactionConfig {
  isolationLevel?:
    | "read uncommitted"
    | "read committed"
    | "repeatable read"
    | "serializable"
    | "snapshot";
}
```


Source: https://orm.drizzle.team/docs/mssql/typebox-legacy

import Npm from '@mdx/Npm.astro';
import Callout from '@mdx/Callout.astro';

# typebox-legacy

### Install the dependencies
<Npm>
drizzle-orm@rc @sinclair/typebox
</Npm>

### Select schema

Defines the shape of data queried from the database - can be used to validate API responses.

```ts copy
import { int, mssqlTable, text } from 'drizzle-orm/mssql-core';
import { createSelectSchema } from 'drizzle-orm/typebox-legacy';
import { Value } from '@sinclair/typebox/value';

const users = mssqlTable('users', {
  id: int().primaryKey().identity(),
  name: text().notNull(),
  age: int().notNull()
});

const userSelectSchema = createSelectSchema(users);

const rows = await db.select({ id: users.id, name: users.name }).from(users).limit(1);
const parsed: { id: number; name: string; age: number } = Value.Parse(userSelectSchema, rows[0]); // Error: `age` is not returned in the above query

const rows = await db.select().from(users).limit(1);
const parsed: { id: number; name: string; age: number } = Value.Parse(userSelectSchema, rows[0]); // Will parse successfully
```

Views are also supported.

```ts copy
import { mssqlView } from 'drizzle-orm/mssql-core';
import { gt } from 'drizzle-orm';
import { createSelectSchema } from 'drizzle-orm/typebox-legacy';
import { Value } from '@sinclair/typebox/value';

const usersView = mssqlView('users_view').as((qb) => qb.select().from(users).where(gt(users.age, 18)));
const usersViewSchema = createSelectSchema(usersView);
const parsed: { id: number; name: string; age: number } = Value.Parse(usersViewSchema, ...);
```

### Insert schema

Defines the shape of data to be inserted into the database - can be used to validate API requests.

```ts copy
import { int, mssqlTable, text } from 'drizzle-orm/mssql-core';
import { createInsertSchema } from 'drizzle-orm/typebox-legacy';
import { Value } from '@sinclair/typebox/value';

const users = mssqlTable('users', {
  id: int().primaryKey().identity(),
  name: text().notNull(),
  age: int().notNull()
});

const userInsertSchema = createInsertSchema(users);

const user = { name: 'John' };
const parsed: { name: string, age: number } = Value.Parse(userInsertSchema, user); // Error: `age` is not defined

const user = { name: 'Jane', age: 30 };
const parsed: { name: string, age: number } = Value.Parse(userInsertSchema, user); // Will parse successfully
await db.insert(users).values(parsed);
```

### Update schema

Defines the shape of data to be updated in the database - can be used to validate API requests.

```ts copy
import { int, mssqlTable, text } from 'drizzle-orm/mssql-core';
import { createUpdateSchema } from 'drizzle-orm/typebox-legacy';
import { Value } from '@sinclair/typebox/value';
import { eq } from "drizzle-orm";

const users = mssqlTable('users', {
  id: int().primaryKey().identity(),
  name: text().notNull(),
  age: int().notNull()
});

const userUpdateSchema = createUpdateSchema(users);

const user = { age: 35 };
const parsed: { name?: string | undefined, age?: number | undefined } = Value.Parse(userUpdateSchema, user); // Will parse successfully
await db.update(users).set(parsed).where(eq(users.name, 'Jane'));
```

### Refinements

Each create schema function accepts an additional optional parameter that you can used to extend, modify or completely overwite a field's schema. Defining a callback function will extend or modify while providing a Typebox schema will overwrite it.

```ts copy
import { int, mssqlTable, text } from 'drizzle-orm/mssql-core';
import { createSelectSchema } from 'drizzle-orm/typebox-legacy';
import { Type } from '@sinclair/typebox';
import { Value } from '@sinclair/typebox/value';

const users = mssqlTable('users', {
  id: int().primaryKey().identity(),
  name: text().notNull(),
  bio: text(),
  preferences: text()
});

const userSelectSchema = createSelectSchema(users, {
  name: (schema) => Type.String({ ...schema, maxLength: 20 }), // Extends schema
  bio: (schema) => Type.String({ ...schema, maxLength: 1000 }), // Extends schema before becoming nullable/optional
  preferences: Type.Object({ theme: Type.String() }) // Overwrites the field, including its nullability
});

const parsed: {
  id: number;
  name: string,
  bio: string | null;
  preferences: {
    theme: string;
  };
} = Value.Parse(userSelectSchema, ...);
```

### Factory functions

For more advanced use cases, you can use the `createSchemaFactory` function.

**Use case: Using an extended Typebox instance**

```ts copy
import { int, mssqlTable, text } from 'drizzle-orm/mssql-core';
import { createSchemaFactory } from 'drizzle-orm/typebox';
import { t } from 'elysia'; // Extended Typebox instance

const users = mssqlTable('users', {
  id: int().primaryKey().identity(),
  name: text().notNull(),
  age: int().notNull()
});
const { createInsertSchema } = createSchemaFactory({ typeboxInstance: t });

const userInsertSchema = createInsertSchema(users, {
  // We can now use the extended instance
  name: (schema) => t.Number({ ...schema, error: "`name` must be a string" }),
});
```

### Data type reference

MSSQL data type mappings follow the MSSQL column builders. See the [MSSQL data types](/docs/mssql/column-types) page for the full column reference.


Source: https://orm.drizzle.team/docs/mssql/typebox

import Npm from '@mdx/Npm.astro';
import Callout from '@mdx/Callout.astro';

# typebox

#### Install the dependencies
<Npm>
drizzle-orm@rc typebox
</Npm>

Allows you to generate [typebox](https://sinclairzx81.github.io/typebox/#/) schemas from Drizzle ORM schemas

**Features**

- Create a select schema for tables.
- Create insert and update schemas for tables.
- Supported dialect: MSSQL.

#### Usage

```ts
import { int, mssqlTable, text, datetime2 } from 'drizzle-orm/mssql-core';
import { createInsertSchema, createSelectSchema, createUpdateSchema } from 'drizzle-orm/typebox';
import { Type } from 'typebox';
import { Value } from 'typebox/value';

const users = mssqlTable('users', {
	id: int().primaryKey().identity(),
	name: text().notNull(),
	email: text().notNull(),
	role: text({ enum: ['admin', 'user'] }).notNull(),
	createdAt: datetime2('created_at').notNull(),
});

// Schema for inserting a user - can be used to validate API requests
const insertUserSchema = createInsertSchema(users);

// Schema for updating a user - can be used to validate API requests
const updateUserSchema = createUpdateSchema(users);

// Schema for selecting a user - can be used to validate API responses
const selectUserSchema = createSelectSchema(users);

// Overriding the fields
const insertUserSchema = createInsertSchema(users, {
	role: Type.String(),
});

// Refining the fields - useful if you want to change the fields before they become nullable/optional in the final schema
const insertUserSchema = createInsertSchema(users, {
	id: (schema) => Type.Number({ ...schema, minimum: 0 }),
	role: Type.String(),
});

// Usage
const isUserValid: boolean = Value.Check(insertUserSchema, {
	name: 'John Doe',
	email: 'johndoe@test.com',
	role: 'admin',
});
```


Source: https://orm.drizzle.team/docs/mssql/update

import Callout from '@mdx/Callout.astro';
import Section from '@mdx/Section.astro';

# SQL Update

<Callout type='info'>
All the values provided to `.set()`are parameterized automatically.
For example, this query:
```ts
await db.update(users).set({ name: "Mr. Dan" }).where(eq(users.name, "Dan"));
```
will be translated to:
```sql
update [users] set [name] = @par0 where [users].[name] = @par1; -- params: ['Mr. Dan', 'Dan']
```
</Callout>

<br/>

The object that you pass to `update` should have keys that match column names in your database schema.
Values of `undefined` are ignored in the object: to set a column to `null`, pass `null`.

```typescript copy
await db.update(users)
  .set({ name: 'Mr. Dan' })
  .where(eq(users.name, 'Dan'));
```
```typescript copy
await db.update(users)
  .set({ name: null })
  .where(eq(users.name, 'Dan'));
```

You can pass SQL as a value to be used in the update object, like this:

```typescript copy
await db.update(users)
  .set({ updatedAt: sql`NOW()` })
  .where(eq(users.name, 'Dan'));
```

### Output

This method allows you to return values from the rows affected by the query. MSSQL supports returning inserted (new row values) and deleted (old row values) values.

If no fields are specified, all inserted values will be returned by default.

```ts
// Update cars and return all new values
const updatedCars: Car[] = await db.update(cars)
  .set({ color: 'red' })
  .output()
  .where(eq(cars.color, 'green'));

// Update cars and return all new values
const updatedCars: Car[] = await db.update(cars)
  .set({ color: 'red' })
  .output({ inserted: true })
  .where(eq(cars.color, 'green'));

// Update cars and return all old values
const updatedCarsIds: { deleted: Car }[] = await db.update(cars)
  .set({ color: 'red' })
  .output({ deleted: true })
  .where(eq(cars.color, 'green'));

// Update cars and return partial old and new values
const beforeAndAfter: { deleted: { oldColor: string }, inserted: { newColor: string } }[] = await db.update(cars)
  .set({ color: 'red' })
  .output({
    deleted: { oldColor: cars.color },
    inserted: { newColor: cars.color }
  })
  .where(eq(cars.color, 'green'));
```

```sql
update [cars] set [color] = 'red' output INSERTED.[name], INSERTED.[color] where [cars].[color] = 'green';
update [cars] set [color] = 'red' output INSERTED.[name], INSERTED.[color] where [cars].[color] = 'green';
update [cars] set [color] = 'red' output DELETED.[name], DELETED.[color] where [cars].[color] = 'green';
update [cars] set [color] = 'red' output INSERTED.[color], DELETED.[color] where [cars].[color] = 'green';
```


Source: https://orm.drizzle.team/docs/mssql/valibot

import Npm from '@mdx/Npm.astro';
import Callout from '@mdx/Callout.astro';

# valibot

### Install the dependencies

<Npm>
drizzle-orm@rc valibot
</Npm>

### Select schema

Defines the shape of data queried from the database - can be used to validate API responses.

```ts copy
import { int, mssqlTable, text } from 'drizzle-orm/mssql-core';
import { createSelectSchema } from 'drizzle-orm/valibot';
import { parse } from 'valibot';

const users = mssqlTable('users', {
  id: int().primaryKey().identity(),
  name: text().notNull(),
  age: int().notNull()
});

const userSelectSchema = createSelectSchema(users);

const rows = await db.select({ id: users.id, name: users.name }).top(1).from(users);
const parsed: { id: number; name: string; age: number } = parse(userSelectSchema, rows[0]); // Error: `age` is not returned in the above query

const rows = await db.select().top(1).from(users);
const parsed: { id: number; name: string; age: number } = parse(userSelectSchema, rows[0]); // Will parse successfully
```

Views are also supported.

```ts copy
import { pgEnum, pgView } from 'drizzle-orm/mssql-core';
import { gt } from 'drizzle-orm';
import { createSelectSchema } from 'drizzle-orm/valibot';
import { parse } from 'valibot';

const usersView = mssqlView('users_view').as((qb) => qb.select().from(users).where(gt(users.age, 18)));
const usersViewSchema = createSelectSchema(usersView);
const parsed: { id: number; name: string; age: number } = parse(usersViewSchema, ...);
```

### Insert schema

Defines the shape of data to be inserted into the database - can be used to validate API requests.

```ts copy
import { int, mssqlTable, text } from 'drizzle-orm/mssql-core';
import { createInsertSchema } from 'drizzle-orm/valibot';
import { parse } from 'valibot';

const users = mssqlTable('users', {
  id: int().primaryKey().identity(),
  name: text().notNull(),
  age: int().notNull()
});

const userInsertSchema = createInsertSchema(users);

const user = { name: 'John' };
const parsed: { name: string, age: number } = parse(userInsertSchema, user); // Error: `age` is not defined

const user = { name: 'Jane', age: 30 };
const parsed: { name: string, age: number } = parse(userInsertSchema, user); // Will parse successfully
await db.insert(users).values(parsed);
```

### Update schema

Defines the shape of data to be updated in the database - can be used to validate API requests.

```ts copy
import { int, mssqlTable, text } from 'drizzle-orm/mssql-core';
import { createUpdateSchema } from 'drizzle-orm/valibot';
import { parse } from 'valibot';

const users = mssqlTable('users', {
  id: int().primaryKey().identity(),
  name: text().notNull(),
  age: int().notNull()
});

const userUpdateSchema = createUpdateSchema(users);

const user = { age: 35 };
const parsed: { name?: string | undefined, age?: number | undefined } = parse(userUpdateSchema, user); // Will parse successfully
await db.update(users).set(parsed).where(eq(users.name, 'Jane'));
```

### Refinements

Each create schema function accepts an additional optional parameter that you can used to extend, modify or completely overwite a field's schema. Defining a callback function will extend or modify while providing a Valibot schema will overwrite it.

```ts copy
import { int, mssqlTable, text } from 'drizzle-orm/mssql-core';
import { createSelectSchema } from 'drizzle-orm/valibot';
import { parse, pipe, maxLength, object, string } from 'valibot';

const users = mssqlTable('users', {
  id: int().primaryKey().identity(),
  name: text().notNull(),
  bio: text(),
  preferences: text()
});

const userSelectSchema = createSelectSchema(users, {
  name: (schema) => pipe(schema, maxLength(20)), // Extends schema
  bio: (schema) => pipe(schema, maxLength(1000)), // Extends schema before becoming nullable/optional
  preferences: object({ theme: string() }) // Overwrites the field, including its nullability
});

const parsed: {
  id: number;
  name: string,
  bio: string | null;
  preferences: {
    theme: string;
  };
} = parse(userSelectSchema, ...);
```

### Data type reference

MSSQL data type mappings follow the MSSQL column builders. See the [MSSQL data types](/docs/mssql/column-types) page for the full column reference.


Source: https://orm.drizzle.team/docs/mssql/views

import Callout from '@mdx/Callout.astro';
import Section from '@mdx/Section.astro';

# Views

There're several ways you can declare views with Drizzle ORM.  

You can declare views that have to be created or you can declare views that already exist in the database. 

You can declare views statements with an inline `query builder` syntax, with `standalone query builder` and with raw `sql` operators. 

When views are created with either inlined or standalone query builders, view columns schema will be automatically inferred, 
yet when you use `sql` you have to explicitly declare view columns schema.

### Declaring views

<Section>
      ```ts filename="schema.ts" copy {14-15}
      import { int, mssqlTable, mssqlView, nvarchar, datetime2 } from "drizzle-orm/mssql-core";
      import { eq } from "drizzle-orm";

      export const user = mssqlTable("user", {
        id: int().identity().primaryKey(),
        name: nvarchar({ length: 256 }),
        email: nvarchar({ length: 256 }),
        password: nvarchar({ length: 256 }),
        role: nvarchar({ length: 256 }).$type<"admin" | "customer">(),
        createdAt: datetime2("created_at"),
        updatedAt: datetime2("updated_at"),
      });

      export const userView = mssqlView("user_view").as((qb) => qb.select().from(user));
      export const customersView = mssqlView("customers_view").as((qb) => qb.select().from(user).where(eq(user.role, "customer")));
      ```
      ```sql
      CREATE VIEW [customers_view] AS select ... from [user] where [user].[role] = 'customer';
      CREATE VIEW [user_view] AS select ... from [user];
      ```
    </Section>

You can also declare views using `standalone query builder`, it works exactly the same way:

<Section>
      ```ts filename="schema.ts" copy {4,16-17}
      import { int, mssqlTable, mssqlView, nvarchar, datetime2, QueryBuilder } from "drizzle-orm/mssql-core";
      import { eq } from "drizzle-orm";

      const qb = new QueryBuilder();

      export const user = mssqlTable("user", {
        id: int().identity().primaryKey(),
        name: nvarchar({ length: 256 }),
        email: nvarchar({ length: 256 }),
        password: nvarchar({ length: 256 }),
        role: nvarchar({ length: 256 }).$type<"admin" | "customer">(),
        createdAt: datetime2("created_at"),
        updatedAt: datetime2("updated_at"),
      });

      export const userView = mssqlView("user_view").as(qb.select().from(user));
      export const customersView = mssqlView("customers_view").as(qb.select().from(user).where(eq(user.role, "customer")));
      ```
      ```sql
      CREATE VIEW [customers_view] AS select ... from [user] where [user].[role] = 'customer';
      CREATE VIEW [user_view] AS select ... from [user];
      ```
    </Section>

### Declaring views with raw SQL
Whenever you need to declare view using a syntax that is not supported by the query builder, 
you can directly use `sql` operator and explicitly specify view columns schema.

```ts copy
import { eq, sql } from "drizzle-orm";
import { int, mssqlTable, mssqlView, nvarchar } from "drizzle-orm/mssql-core";

export const users = mssqlTable("users", {
  id: int().identity().primaryKey(),
  name: nvarchar({ length: 256 }),
  cityId: int("city_id"),
});

export const newYorkers = mssqlView("new_yorkers", {
  id: int().primaryKey(),
  name: nvarchar({ length: 256 }).notNull(),
  cityId: int("city_id").notNull(),
}).as(sql`select * from ${users} where ${eq(users.cityId, 1)}`);
```
```sql
CREATE VIEW [new_yorkers] AS select * from [users] where [users].[city_id] = 1;
```

### Declaring existing views
When you're provided with a read only access to an existing view in the database you should use `.existing()` view configuration, 
`drizzle-kit` will ignore and will not generate a `create view` statement in the generated migration.

```ts {17}
import { int, mssqlTable, mssqlView, nvarchar, datetime2 } from "drizzle-orm/mssql-core";

export const user = mssqlTable("user", {
  id: int().identity().primaryKey(),
  name: nvarchar({ length: 256 }),
  email: nvarchar({ length: 256 }),
  password: nvarchar({ length: 256 }),
  role: nvarchar({ length: 256 }).$type<"admin" | "customer">(),
  createdAt: datetime2("created_at"),
  updatedAt: datetime2("updated_at"),
});

export const trimmedUser = mssqlView("trimmed_user", {
  id: int("id"),
  name: nvarchar("name", { length: 256 }),
  email: nvarchar("email", { length: 256 }),
}).existing();
```

### Extended example
<Callout type="info" emoji="ℹ️">
All the parameters inside the query will be inlined, instead of being parameterised.
</Callout>

```ts copy
export const newYorkers = mssqlView('new_yorkers')
  .with({
    encryption: true,
    schemaBinding: false,
    viewMetadata: true,
    checkOption: true,
  })
  .as((qb) => {
    const sq = qb.$with('sq').as(
      qb
        .select({
          userId: users.id.as('user_id'),
          cityId: cities.id.as('city_id'),
        })
        .from(users)
        .leftJoin(cities, eq(cities.id, users.homeCity))
        .where(sql`${users.age1} > 18 and ${users.homeCity} = 1`),
    );

    return qb.with(sq).select().from(sq);
  });
```
```sql
CREATE VIEW [new_yorkers]
WITH ENCRYPTION, VIEW_METADATA 
AS
WITH
	[sq] AS (
		SELECT
			[users].[id] AS [user_id],
			[cities].[id] AS [city_id]
		FROM
			[users]
			LEFT JOIN [cities] ON [cities].[id] = [users].[home_city]
		WHERE
			[users].[age1] > 18
			AND [users].[home_city] = 1
	)
SELECT
	[user_id],
	[city_id]
FROM
	[sq]
WITH
	CHECK
OPTION;
```


Source: https://orm.drizzle.team/docs/mssql/zod

import Npm from '@mdx/Npm.astro';
import Callout from '@mdx/Callout.astro';

# zod

### Install the dependencies

<Npm>
drizzle-orm@rc zod
</Npm>

### Select schema

Defines the shape of data queried from the database - can be used to validate API responses.

```ts copy
import { int, mssqlTable, text } from 'drizzle-orm/mssql-core';
import { createSelectSchema } from 'drizzle-orm/zod';

const users = mssqlTable('users', {
  id: int().primaryKey().identity(),
  name: text().notNull(),
  age: int().notNull()
});

const userSelectSchema = createSelectSchema(users);

const rows = await db.select({ id: users.id, name: users.name }).top(1).from(users);
const parsed: { id: number; name: string; age: number } = userSelectSchema.parse(rows[0]); // Error: `age` is not returned in the above query

const rows = await db.select().top(1).from(users);
const parsed: { id: number; name: string; age: number } = userSelectSchema.parse(rows[0]); // Will parse successfully
```

Views are also supported.
```ts copy
import { createSelectSchema } from 'drizzle-orm/zod';
import { mssqlView } from 'drizzle-orm/mssql-core';
 
const usersView = mssqlView('users_view').as((qb) => qb.select().from(users).where(gt(users.age, 18)));
const usersViewSchema = createSelectSchema(usersView);
const parsed: { id: number; name: string; age: number } = usersViewSchema.parse(...);
```

### Insert schema

Defines the shape of data to be inserted into the database - can be used to validate API requests.

```ts copy
import { int, mssqlTable, text } from 'drizzle-orm/mssql-core';
import { createInsertSchema } from 'drizzle-orm/zod';

const users = mssqlTable('users', {
  id: int().primaryKey().identity(),
  name: text().notNull(),
  age: int().notNull()
});

const userInsertSchema = createInsertSchema(users);

const user = { name: 'John' };
const parsed: { name: string, age: number } = userInsertSchema.parse(user); // Error: `age` is not defined

const user = { name: 'Jane', age: 30 };
const parsed: { name: string, age: number } = userInsertSchema.parse(user); // Will parse successfully
await db.insert(users).values(parsed);
```

### Update schema

Defines the shape of data to be updated in the database - can be used to validate API requests.

```ts copy
import { int, mssqlTable, text } from 'drizzle-orm/mssql-core';
import { createUpdateSchema } from 'drizzle-orm/zod';
import { eq } from 'drizzle-orm';

const users = mssqlTable('users', {
  id: int().primaryKey().identity(),
  name: text().notNull(),
  age: int().notNull()
});

const userUpdateSchema = createUpdateSchema(users);

const user = { age: 35 };
const parsed: { name?: string | undefined, age?: number | undefined } = userUpdateSchema.parse(user); // Will parse successfully
await db.update(users).set(parsed).where(eq(users.name, 'Jane'));
```

### Refinements

Each create schema function accepts an additional optional parameter that you can used to extend, modify or completely overwite a field's schema. Defining a callback function will extend or modify while providing a Zod schema will overwrite it.

```ts copy
import { int, mssqlTable, text } from 'drizzle-orm/mssql-core';
import { createSelectSchema } from 'drizzle-orm/zod';
import { z } from 'zod/v4';

const users = mssqlTable('users', {
  id: int().primaryKey(),
  name: text().notNull(),
  bio: text(),
  preferences: text()
});

const userSelectSchema = createSelectSchema(users, {
  name: (schema) => schema.max(20), // Extends schema
  bio: (schema) => schema.max(1000), // Extends schema before becoming nullable/optional
  preferences: z.object({ theme: z.string() }) // Overwrites the field, including its nullability
});

const parsed: {
  id: number;
  name: string,
  bio: string | null;
  preferences: {
    theme: string;
  };
} = userSelectSchema.parse(...);
```

### Factory functions

For more advanced use cases, you can use the `createSchemaFactory` function.

**Use case: Using an extended Zod instance**

```ts copy
import { int, mssqlTable, text } from 'drizzle-orm/mssql-core';
import { createSchemaFactory } from 'drizzle-orm/zod';
import { z } from '@hono/zod-openapi'; // Extended Zod instance

const users = mssqlTable('users', {
  id: int().primaryKey().identity(),
  name: text().notNull(),
  age: int().notNull()
});

const { createInsertSchema } = createSchemaFactory({ zodInstance: z });

const userInsertSchema = createInsertSchema(users, {
  // We can now use the extended instance
  name: (schema) => schema.openapi({ example: 'John' })
});
```

**Use case: Type coercion**

```ts copy
import { mssqlTable, datetime2 } from 'drizzle-orm/mssql-core';
import { createSchemaFactory } from 'drizzle-orm/zod';
import { z } from 'zod/v4';

const users = mssqlTable('users', {
  ...,
  createdAt: datetime2().notNull()
});

const { createInsertSchema } = createSchemaFactory({
  // This configuration will only coerce dates. Set `coerce` to `true` to coerce all data types or specify others
  coerce: {
    date: true
  }
});

const userInsertSchema = createInsertSchema(users);
// The above is the same as this:
const userInsertSchema = z.object({
  ...,
  createdAt: z.coerce.date()
});
```

### Data type reference

MSSQL data type mappings follow the MSSQL column builders. See the [MSSQL data types](/docs/mssql/column-types) page for the full column reference.


Source: https://orm.drizzle.team/docs/mysql/aliases

import Section from '@mdx/Section.astro';

# Aliases
Drizzle supports aliasing for tables, columns, subqueries and CTEs — mapping directly to the SQL `AS` keyword.

### Table aliasing
You can alias tables using the `alias` function. This is useful when you need to join the same table multiple times, 
for example in self-referencing relationships like employees and their managers:

<Section>
```ts copy {9}
import { alias, mysqlTable, int, text } from "drizzle-orm/mysql-core";

const employees = mysqlTable("employees", {
  id: int().autoincrement().primaryKey(),
  name: text(),
  managerId: int("manager_id"),
});

const manager = alias(employees, "manager");

await db.select({
  employeeName: employees.name,
  managerName: manager.name,
})
  .from(employees)
  .leftJoin(manager, eq(employees.managerId, manager.id));
```
```sql
select `employees`.`name`, `manager`.`name`
from `employees`
left join `employees` `manager` on `employees`.`manager_id` = `manager`.`id`;
```
</Section>

### Column aliasing
You can alias columns using the `.as()` method on columns and `sql` expressions.
This maps directly to the SQL `AS` keyword and lets you control the name of a column in the query result:

<Section>
```ts {3}
const result = await db.select({
  id: users.id,
  lowerName: users.name.as("lower_name"),
}).from(users);
```
```sql
select `id`, `name` as `lower_name` from `users`;
```
</Section>

You can also use `.as()` with `sql` expressions:

<Section>
```ts {3}
const result = await db.select({
  id: users.id,
  lowerName: sql<string>`lower(${users.name})`.as("lower_name"),
}).from(users);
```
```sql
select `id`, lower(`name`) as `lower_name` from `users`;
```
</Section>

### Subquery aliasing
When using a subquery as a data source, you must provide an alias using `.as()`. 
This lets you reference the subquery's columns in the outer query:

<Section>
```ts
const sq = db.select().from(users).where(eq(users.id, 42)).as('sq');

const result = await db.select().from(sq);
```
```sql
select `id`, `name`, `age` from (select `id`, `name`, `age` from `users` where `users`.`id` = 42) `sq`;
```
</Section>

Subqueries can also be used in joins:

<Section>
```ts
const sq = db.select().from(users).where(eq(users.id, 42)).as('sq');

const result = await db.select().from(users).leftJoin(sq, eq(users.id, sq.id));
```
```sql
select `users`.`id`, `users`.`name`, `users`.`age`, `sq`.`id`, `sq`.`name`, `sq`.`age`
  from `users`
  left join (select `id`, `name`, `age` from `users` where `users`.`id` = 42) `sq`
    on `users`.`id` = `sq`.`id`;
```
</Section>

### CTE aliasing
Common table expressions (CTEs) are aliased using `db.$with('alias')`. 
The alias name is used to reference the CTE in the main query:

<Section>
```ts
const sq = db.$with('sq').as(db.select().from(users).where(eq(users.id, 42)));

const result = await db.with(sq).select().from(sq);
```
```sql
with `sq` as (select `id`, `name`, `age` from `users` where `users`.`id` = 42)
select `id`, `name`, `age` from `sq`;
```
</Section>

When using `sql` expressions inside a CTE, you need to alias them with `.as()` to be able to reference them in the outer query:

<Section>
```ts
const sq = db.$with('sq').as(db.select({
  name: sql<string>`upper(${users.name})`.as('name'),
}).from(users));

const result = await db.with(sq).select({ name: sq.name }).from(sq);
```
```sql
with `sq` as (select upper(`name`) as `name` from `users`)
select `name` from `sq`;
```
</Section>

Source: https://orm.drizzle.team/docs/mysql/arktype

import Npm from '@mdx/Npm.astro';
import Callout from '@mdx/Callout.astro';

# arktype

### Install the dependencies

<Npm>
drizzle-orm@rc arktype
</Npm>

### Select schema

Defines the shape of data queried from the database - can be used to validate API responses.

```ts copy
import { int, mysqlTable, text } from 'drizzle-orm/mysql-core';
import { createSelectSchema } from 'drizzle-orm/arktype';
import type { ArkErrors } from "arktype";

const users = mysqlTable('users', {
  id: int().primaryKey().autoincrement(),
  name: text().notNull(),
  age: int().notNull()
});

const userSelectSchema = createSelectSchema(users);

const rows = await db.select({ id: users.id, name: users.name }).from(users).limit(1);
const parsed: ArkErrors | { id: number; name: string; age: number } = userSelectSchema(rows[0]); // Error: `age` is not returned in the above query

const rows = await db.select().from(users).limit(1);
const parsed: ArkErrors | { id: number; name: string; age: number } = userSelectSchema(rows[0]); // Will parse successfully
```

Views are also supported.

```ts copy
import { mysqlView } from 'drizzle-orm/mysql-core';
import { gt } from 'drizzle-orm';
import { createSelectSchema } from 'drizzle-orm/arktype';

const usersView = mysqlView('users_view').as((qb) => qb.select().from(users).where(gt(users.age, 18)));
const usersViewSchema = createSelectSchema(usersView);
const parsed: ArkErrors | { id: number; name: string; age: number } = usersViewSchema(...);
```

### Insert schema

Defines the shape of data to be inserted into the database - can be used to validate API requests.

```ts copy
import { int, mysqlTable, text } from 'drizzle-orm/mysql-core';
import { createInsertSchema } from 'drizzle-orm/arktype';
import type { ArkErrors } from "arktype";

const users = mysqlTable('users', {
  id: int().primaryKey().autoincrement(),
  name: text().notNull(),
  age: int().notNull()
});

const userInsertSchema = createInsertSchema(users);

const user = { name: 'John' };
const parsed: ArkErrors | { id?: number | undefined, name: string, age: number } = userInsertSchema(user); // Error: `age` is not defined

const user = { name: 'Jane', age: 30 };
const parsed: ArkErrors | { id?: number | undefined, name: string, age: number } = userInsertSchema(user); // Will parse successfully

if (parsed instanceof ArkErrors) {
  console.error(parsed.summary);
  process.exit(1);
}

await db.insert(users).values(parsed);
```

### Update schema

Defines the shape of data to be updated in the database - can be used to validate API requests.

```ts copy
import { int, mysqlTable, text } from 'drizzle-orm/mysql-core';
import { createUpdateSchema } from 'drizzle-orm/arktype';
import { parse } from 'arktype';
import { ArkErrors } from "arktype";
import { eq } from "drizzle-orm";

const users = mysqlTable('users', {
  id: int().primaryKey().autoincrement(),
  name: text().notNull(),
  age: int().notNull()
});

const userUpdateSchema = createUpdateSchema(users);

const user = { age: 35 };
const parsed:  ArkErrors | { id?: number | undefined, name?: string | undefined, age?: number | undefined } = userUpdateSchema(user); // Will parse successfully

if (parsed instanceof ArkErrors) {
  console.error(parsed.summary);
  process.exit(1);
}

await db.update(users).set(parsed).where(eq(users.name, 'Jane'));
```

### Refinements

Each create schema function accepts an additional optional parameter that you can used to extend, modify or completely overwite a field's schema. Defining a callback function will extend or modify while providing a arktype schema will overwrite it.

```ts copy
import { int, json, mysqlTable, text } from 'drizzle-orm/mysql-core';
import { createSelectSchema } from 'drizzle-orm/arktype';
import { ArkErrors, type } from 'arktype';

const users = mysqlTable('users', {
  id: int().primaryKey().autoincrement(),
  name: text().notNull(),
  bio: text(),
  preferences: json()
});

const userSelectSchema = createSelectSchema(users, {
  name: (schema) => pipe(schema, maxLength(20)), // Extends schema
  bio: (schema) => pipe(schema, maxLength(1000)), // Extends schema before becoming nullable/optional
  preferences: object({ theme: string() }) // Overwrites the field, including its nullability
});

const parsed: ArkErrors | {
  id: number;
  name: string,
  bio?: string | undefined;
  preferences: {
    theme: string;
  };
} = userSelectSchema(...);
```

### Data type reference

```ts
mysql.boolean();

// Schema
type.boolean;
```

```ts
mysql.mysqlEnum('name', ['val1', 'val2']);

// Schema
type.enumerated('val1', 'val2')
```

```ts
mysql.date({ mode: 'date' });
mysql.datetime({ mode: 'date' });
mysql.timestamp({ mode: 'date' });

// Schema
type.Date;
```

```ts
mysql.binary();
mysql.date({ mode: 'string' });
mysql.datetime({ mode: 'string' });
mysql.decimal();
mysql.time();
mysql.timestamp({ mode: 'string' });
mysql.varbinary();

// Schema
type.string;
```

```ts
mysql.tinyblob({ mode: 'string' });
mysql.tinyblob();

type.string.atMostLength(255)
```

```ts
mysql.blob({ mode: 'string' });
mysql.blob();

type.string.atMostLength(65_535)
```

```ts
mysql.mediumblob({ mode: 'string' });
mysql.mediumblob();

type.string.atMostLength(16_777_215)
```

```ts
mysql.longblob({ mode: 'string' });
mysql.longblob();

type.string.atMostLength(4_294_967_295)
```

```ts
mysql.char({ length: ... });

// Schema
type.string.exactlyLength(length);
```

```ts
mysql.varchar({ length: ... });

// Schema
type.string.atMostLength(length);
```

```ts
binary({ length: ... });

// Schema
type(`/^[01]{0,${length ?? "*"}}$/`)
```

```ts
mysql.varbinary({ length: ... });

// Schema
type(`/^[01]{0,${length ?? "*"}}$/`)
```

```ts
mysql.tinytext();

// Schema
type.string.atMostLength(255); // unsigned 8-bit integer limit
```

```ts
mysql.text();

// Schema
type.string.atMostLength(65_535); // unsigned 16-bit integer limit
```

```ts
mysql.mediumtext();

// Schema
type.string.atMostLength(16_777_215); // unsigned 24-bit integer limit
```

```ts
mysql.longtext();

// Schema
type.string.atMostLength(4_294_967_295); // unsigned 32-bit integer limit
```

```ts
mysql.tinytext({ enum: ... });
mysql.mediumtext({ enum: ... });
mysql.text({ enum: ... });
mysql.longtext({ enum: ... });
mysql.char({ enum: ... });
mysql.varchar({ enum: ... });

// Schema
type.enumerated(...enum);
```

```ts
mysql.tinyint();

// Schema
type.keywords.number.integer.atLeast(-128).atMost(127); // 8-bit integer lower and upper limit
```

```ts
mysql.tinyint({ unsigned: true });

// Schema
type.keywords.number.integer.atLeast(0).atMost(255); // unsigned 8-bit integer lower and upper limit
```

```ts
mysql.smallint();

// Schema
type.keywords.number.integer.atLeast(-32_768).atMost(32_767); // 16-bit integer lower and upper limit
```

```ts
mysql.smallint({ unsigned: true });

// Schema
type.keywords.number.integer.atLeast(0).atMost(65_535); // unsigned 16-bit integer lower and upper limit
```

```ts
mysql.float();

// Schema
type.number.atLeast(-8_388_608).atMost(8_388_607); // 24-bit integer lower and upper limit
```

```ts
mysql.mediumint();

// Schema
type.keywords.number.integer.atLeast(-8_388_608).atMost(8_388_607); // 24-bit integer lower and upper limit
```

```ts
mysql.float({ unsigned: true });

// Schema
type.number.atLeast(0).atMost(16_777_215); // unsigned 24-bit integer lower and upper limit
```

```ts
mysql.mediumint({ unsigned: true });

// Schema
type.keywords.number.integer.atLeast(0).atMost(16_777_215); // unsigned 24-bit integer lower and upper limit
```

```ts
mysql.int();

// Schema
type.keywords.number.integer.atLeast(-2_147_483_648).atMost(2_147_483_647); // 32-bit integer lower and upper limit
```

```ts
mysql.int({ unsigned: true });

// Schema
type.keywords.number.integer.atLeast(0).atMost(4_294_967_295); // unsgined 32-bit integer lower and upper limit
```

```ts
mysql.double();
mysql.real();

// Schema
type.number.atLeast(-140_737_488_355_328).atMost(140_737_488_355_327); // 48-bit integer lower and upper limit
```

```ts
mysql.double({ unsigned: true });

// Schema
type.number.atLeast(0).atMost(281_474_976_710_655); // unsigned 48-bit integer lower and upper limit
```

```ts
mysql.decimal({ mode: 'number' });

// Schema
type.number.atLeast(9_007_199_254_740_991).atMost(9_007_199_254_740_991)
```

```ts
mysql.decimal({ mode: 'bigint' });

// Schema
type.bigint.narrow(
  (value, ctx) => value < -9_223_372_036_854_775_808n ? ctx.mustBe('greater than') : value > 9_223_372_036_854_775_807n ? ctx.mustBe('less than') : true
); // 64-bit integer lower and upper limit
```

```ts
mysql.decimal({ mode: 'number', unsigned: true });

// Schema
type.number.atLeast(0).atMost(9_007_199_254_740_991)
```

```ts
mysql.decimal({ mode: 'bigint', unsigned: true });

// Schema
type.bigint.narrow(
  (value, ctx) => value < 0n ? ctx.mustBe('greater than') : value > 18_446_744_073_709_551_615n ? ctx.mustBe('less than') : true
); // unsigned 64-bit integer lower and upper limit
```

```ts
mysql.bigint({ mode: 'number' });

// Schema
type.keywords.number.integer.atLeast(-9_007_199_254_740_991).atMost(9_007_199_254_740_991); // Javascript min. and max. safe integers
```

```ts
mysql.bigint({ mode: 'number', unsigned: true });

// Schema
type.keywords.number.integer.atLeast(0).atMost(9_007_199_254_740_991); // Javascript min. and max. safe integers
```

```ts
mysql.bigint({ mode: 'string' });

// Schema
type.string.narrow((v, ctx) => {
	if (typeof v !== 'string') {
		return ctx.mustBe('a string');
	}
	if (!(/^-?\d+$/.test(v))) {
		return ctx.mustBe('a string representing a number');
	}

	const bigint = BigInt(v);
	if (bigint < -9_223_372_036_854_775_808n) {
		return ctx.mustBe('greater than');
	}
	if (bigint > 9_223_372_036_854_775_807n) {
		return ctx.mustBe('less than');
	}

	return true;
});
```

```ts
mysql.bigint({ mode: 'string', unsigned: true });

// Schema
type.string.narrow((v, ctx) => {
	if (typeof v !== 'string') {
		return ctx.mustBe('a string');
	}
	if (!(/^\d+$/.test(v))) {
		return ctx.mustBe('a string representing a number');
	}

	const bigint = BigInt(v);
	if (bigint < 0) {
		return ctx.mustBe('greater than');
	}
	if (bigint > 9_223_372_036_854_775_807n) {
		return ctx.mustBe('less than');
	}

	return true;
});
```

```ts
mysql.bigint({ mode: 'bigint' });

// Schema
type.bigint.narrow(
  (value, ctx) => value < -9_223_372_036_854_775_808n ? ctx.mustBe('greater than') : value > 9_223_372_036_854_775_807n ? ctx.mustBe('less than') : true
); // 64-bit integer lower and upper limit
```

```ts
mysql.bigint({ mode: 'bigint', unsigned: true });

// Schema
type.bigint.narrow(
  (value, ctx) => value < 0n ? ctx.mustBe('greater than') : value > 18_446_744_073_709_551_615n ? ctx.mustBe('less than') : true
); // unsigned 64-bit integer lower and upper limit
```

```ts
mysql.serial();

// Schema
type.keywords.number.integer.atLeast(0).atMost(9_007_199_254_740_991); // Javascript max. safe integer
```

```ts
mysql.year();

// Schema
type.keywords.number.integer.atLeast(1_901).atMost(2_155);
```

```ts
mysql.json();

// Schema
type('string | number | boolean | null').or(type('unknown.any[] | Record<string, unknown.any>'));
```


Source: https://orm.drizzle.team/docs/mysql/cache

import Callout from '@mdx/Callout.astro';
import Npm from '@mdx/Npm.astro';

# Cache

Drizzle sends every query straight to your database by default. There are no hidden actions, no automatic caching 
or invalidation - you'll always see exactly what runs. If you want caching, you must opt in.

By default, Drizzle uses a `explicit` caching strategy (i.e. `global: false`), so nothing is ever cached unless you ask. 
This prevents surprises or hidden performance traps in your application. 
Alternatively, you can flip on `all` caching (`global: true`) so that every select will look in cache first.

## Quickstart

### Upstash integration

Drizzle provides an `upstashCache()` helper out of the box. By default, this uses Upstash Redis with automatic configuration if environment variables are set.

```ts
import { upstashCache } from "drizzle-orm/cache/upstash";
import { drizzle } from "drizzle-orm/mysql2";

const db = drizzle(process.env.DB_URL!, {
  cache: upstashCache({ token: process.env.UPSTASH_TOKEN, url: process.env.UPSTASH_URL }),
});
```

You can also explicitly define your Upstash credentials, enable global caching for all queries by default or pass custom caching options:

```ts
import { upstashCache } from "drizzle-orm/cache/upstash";
import { drizzle } from "drizzle-orm/mysql2";

const db = drizzle(process.env.DB_URL!, {
  cache: upstashCache({
    // 👇 Redis credentials (optional — can also be pulled from env vars)
    url: '<UPSTASH_URL>',
    token: '<UPSTASH_TOKEN>',

    // 👇 Enable caching for all queries by default (optional)
    global: true,

    // 👇 Default cache behavior (optional)
    config: { ex: 60 }
  })
});
```

## Cache config reference

Drizzle supports the following cache config options for Upstash:

```ts
export type CacheConfig = {
  /**
   * Expiration in seconds (positive integer)
   */
  ex?: number;
  /**
   * Set an expiration (TTL or time to live) on one or more fields of a given hash key.
   * Used for HEXPIRE command
   */
  hexOptions?: "NX" | "nx" | "XX" | "xx" | "GT" | "gt" | "LT" | "lt";
};
```

## Cache usage examples

Once you've configured caching, here's how the cache behaves:

**Case 1: Drizzle with `global: false` (default, opt-in caching)**

```ts
import { upstashCache } from "drizzle-orm/cache/upstash";
import { drizzle } from "drizzle-orm/mysql2";

const db = drizzle(process.env.DB_URL!, {
  // 👇 `global: true` is not passed, false by default
  cache: upstashCache({ url: "", token: "" }),
});
```

In this case, the following query won't read from cache

```ts
const res = await db.select().from(users);

// Any mutate operation will still trigger the cache's onMutate handler
// and attempt to invalidate any cached queries that involved the affected tables
await db.insert(users).value({ email: "cacheman@upstash.com" });
```

To make this query read from the cache, call `.$withCache()`

```ts
const res = await db.select().from(users).$withCache();
```

`.$withCache` has a set of options you can use to manage and configure this specific query strategy

```ts
// rewrite the config for this specific query
.$withCache({ config: {} })

// give this query a custom cache key (instead of hashing query+params under the hood)
.$withCache({ tag: 'custom_key' })

// turn off auto-invalidation for this query
// note: this leads to eventual consistency (explained below)
.$withCache({ autoInvalidate: false })
```

<Callout>
**Eventual consistency example**

This example is only relevant if you manually set `autoInvalidate: false`. By default, `autoInvalidate` is enabled. 

You might want to turn off `autoInvalidate` if:
- your data doesn't change often, and slight staleness is acceptable (e.g. product listings, blog posts)
- you handle cache invalidation manually

In those cases, turning it off can reduce unnecessary cache invalidation. However, in most cases, we recommend keeping the default enabled.

Example: Imagine you cache the following query on `usersTable` with a 3-second TTL:

``` ts
const recent = await db
  .select().from(usersTable)
  .$withCache({ config: { ex: 3 }, autoInvalidate: false });
```

If someone runs `db.insert(usersTable)...` the cache won't be invalidated immediately. For up to 3 seconds, you'll keep seeing the old data until it eventually becomes consistent.
</Callout>

**Case 2: Drizzle with `global: true` option**

```ts
import { upstashCache } from "drizzle-orm/cache/upstash";
import { drizzle } from "drizzle-orm/mysql2";

const db = drizzle(process.env.DB_URL!, {
  cache: upstashCache({ url: "", token: "", global: true }),
});
```

In this case, the following query will read from cache

```ts
const res = await db.select().from(users);
```

If you want to disable cache for this specific query, call `.$withCache(false)`

```ts
// disable cache for this query
const res = await db.select().from(users).$withCache(false);
```

You can also use cache instance from a `db` to invalidate specific tables or tags

```ts
// Invalidate all queries that use the `users` table. You can do this with the Drizzle instance.
await db.$cache.invalidate({ tables: users });
// or
await db.$cache.invalidate({ tables: [users, posts] });

// Invalidate all queries that use the `usersTable`. You can do this by using just the table name.
await db.$cache.invalidate({ tables: "usersTable" });
// or
await db.$cache.invalidate({ tables: ["usersTable", "postsTable"] });

// You can also invalidate custom tags defined in any previously executed select queries.
await db.$cache.invalidate({ tags: "custom_key" });
// or
await db.$cache.invalidate({ tags: ["custom_key", "custom_key1"] });
```

## Custom cache

This example shows how to plug in a custom `cache` in Drizzle: you provide functions to fetch data from the cache, store results back into cache, and invalidate entries whenever a mutation runs.

Cache extension provides this set of config options
```ts
export type CacheConfig = {
  /** expire time, in seconds */
  ex?: number;
  /** expire time, in milliseconds */
  px?: number;
  /** Unix time (sec) at which the key will expire */
  exat?: number;
  /** Unix time (ms) at which the key will expire */
  pxat?: number;
  /** retain existing TTL when updating a key */
  keepTtl?: boolean;
  /** options for HEXPIRE (hash-field TTL) */
  hexOptions?: 'NX' | 'XX' | 'GT' | 'LT' | 'nx' | 'xx' | 'gt' | 'lt';
};
```

```ts
const db = drizzle(process.env.DB_URL!, { cache: new TestGlobalCache() });
```

```ts
import Keyv from "keyv";

export class TestGlobalCache extends Cache {
  private globalTtl: number = 1000;
  // This object will be used to store which query keys were used
  // for a specific table, so we can later use it for invalidation.
  private usedTablesPerKey: Record<string, string[]> = {};

  constructor(private kv: Keyv = new Keyv()) {
    super();
  }

  // For the strategy, we have two options:
  // - 'explicit': The cache is used only when .$withCache() is added to a query.
  // - 'all': All queries are cached globally.
  // The default behavior is 'explicit'.
  override strategy(): "explicit" | "all" {
    return "all";
  }

  // This function accepts query and parameters that cached into key param,
  // allowing you to retrieve response values for this query from the cache.
  override async get(key: string): Promise<any[] | undefined> {
    const res = (await this.kv.get(key)) ?? undefined;
    return res;
  }

  // This function accepts several options to define how cached data will be stored:
  // - 'key': A hashed query and parameters.
  // - 'response': An array of values returned by Drizzle from the database.
  // - 'tables': An array of tables involved in the select queries. This information is needed for cache invalidation.
  // - 'isTag': A boolean flag indicating whether this cache entry represents a tag-based query.
  //    When true, the entry is associated with a specific tag rather than table-level invalidation,
  //    allowing you to invalidate cached queries by tag name. See the UpstashCache:
  //    https://github.com/drizzle-team/drizzle-orm/blob/beta/drizzle-orm/src/cache/upstash/cache.ts for an example
  //
  // For example, if a query uses the "users" and "posts" tables, you can store this information. Later, when the app executes
  // any mutation statements on these tables, you can remove the corresponding key from the cache.
  // If you're okay with eventual consistency for your queries, you can skip this option.
  override async put(
    key: string,
    response: any,
    tables: string[],
    isTag: boolean = false,
    config?: CacheConfig,
  ): Promise<void> {
    const ttl = config?.px ?? (config?.ex ? config.ex * 1000 : this.globalTtl);

    await this.kv.set(key, response, ttl);

    for (const table of tables) {
      const keys = this.usedTablesPerKey[table];
      if (keys === undefined) {
        this.usedTablesPerKey[table] = [key];
      } else {
        keys.push(key);
      }
    }
  }

  // This function is called when insert, update, or delete statements are executed.
  // You can either skip this step or invalidate queries that used the affected tables.
  //
  // The function receives an object with two keys:
  // - 'tags': Used for queries labeled with a specific tag, allowing you to invalidate by that tag.
  // - 'tables': The actual tables affected by the insert, update, or delete statements,
  //   helping you track which tables have changed since the last cache update.
  override async onMutate(params: {
    tags: string | string[];
    tables: string | string[] | Table<any> | Table<any>[];
  }): Promise<void> {
    const tagsArray = params.tags
      ? Array.isArray(params.tags)
        ? params.tags
        : [params.tags]
      : [];
    const tablesArray = params.tables
      ? Array.isArray(params.tables)
        ? params.tables
        : [params.tables]
      : [];

    const keysToDelete = new Set<string>();

    for (const table of tablesArray) {
      const tableName = is(table, Table)
        ? getTableName(table)
        : (table as string);
      const keys = this.usedTablesPerKey[tableName] ?? [];
      for (const key of keys) keysToDelete.add(key);
    }

    if (keysToDelete.size > 0 || tagsArray.length > 0) {
      for (const tag of tagsArray) {
        await this.kv.delete(tag);
      }

      for (const key of keysToDelete) {
        await this.kv.delete(key);
        for (const table of tablesArray) {
          const tableName = is(table, Table)
            ? getTableName(table)
            : (table as string);
          this.usedTablesPerKey[tableName] = [];
        }
      }
    }
  }
}
```

## Limitations

#### Queries that won't be handled by the `cache` extension:

- Using cache with raw queries, such as:

```ts
db.execute(sql`select 1`);
```

- Using cache in transactions
```ts
await db.transaction(async (tx) => {
  await tx.update(accounts).set(...).where(...);
  await tx.update...
});
```

#### Limitations that are temporary and will be handled soon:

- Using cache with Drizzle Relational Queries
```ts
await db.query.users.findMany();
```

- Using cache with views


Source: https://orm.drizzle.team/docs/mysql/column-types

import Section from '@mdx/Section.astro';
import Callout from '@mdx/Callout.astro';

We have native support for all of them, yet if that's not enough for you, feel free to create **[custom types](/docs/mysql/custom-types)**.

<Callout title='important' type='warning'>
All examples in this part of the documentation do not use database column name aliases, and column names are generated from TypeScript keys. 

You can use database aliases in column names if you want, and you can also use the `casing API` to define a mapping strategy for Drizzle.

You can read more about it [here](/docs/mysql/sql-schema-declaration#shape-your-data-schema)
</Callout>

<Callout title='important' type='info'>
All integer types (`int`, `tinyint`, `smallint`, `mediumint`, `bigint`) are `signed` by default, allowing both negative and positive values. 
Adding `{ unsigned: true }` restricts the column to non-negative values only but doubles the upper range.
</Callout>

### integer

A `4`-byte integer with a range of `-2,147,483,648` to `2,147,483,647` signed, or `0` to `4,294,967,295` unsigned

For more info please refer to the official MySQL **[docs.](https://dev.mysql.com/doc/refman/8.0/en/integer-types.html)**

<Section>
```typescript
import { int, mysqlTable } from "drizzle-orm/mysql-core";

export const table = mysqlTable('table', {
	int: int(),
	int2: int({ unsigned: true })
});
```

```sql
CREATE TABLE `table` (
	`int` int,
	`int2` int unsigned
);
```
</Section>

### tinyint

A `1`-byte integer with a range of `-128` to `127` signed, or `0` to `255` unsigned

For more info please refer to the official MySQL **[docs.](https://dev.mysql.com/doc/refman/8.0/en/integer-types.html)**

<Section>
```typescript
import { tinyint, mysqlTable } from "drizzle-orm/mysql-core";

export const table = mysqlTable('table', {
	tinyint: tinyint(),
	tinyint2: tinyint({ unsigned: true })
});
```

```sql
CREATE TABLE `table` (
	`tinyint` tinyint,
	`tinyint2` tinyint unsigned
);
```
</Section>

### smallint

A `2`-byte integer with a range of `-32,768` to `32,767` signed, or `0` to `65,535` unsigned

For more info please refer to the official MySQL **[docs.](https://dev.mysql.com/doc/refman/8.0/en/integer-types.html)**

<Section>
```typescript
import { smallint, mysqlTable } from "drizzle-orm/mysql-core";

export const table = mysqlTable('table', {
	smallint: smallint(),
	smallint2: smallint({ unsigned: true }),
});
```

```sql
CREATE TABLE `table` (
	`smallint` smallint,
	`smallint2` smallint unsigned
);
```
</Section>

### mediumint

A `3`-byte integer with a range of `-8,388,608` to `8,388,607` signed, or `0` to `16,777,215` unsigned

For more info please refer to the official MySQL **[docs.](https://dev.mysql.com/doc/refman/8.0/en/integer-types.html)**

<Section>
```typescript
import { mediumint, mysqlTable } from "drizzle-orm/mysql-core";

export const table = mysqlTable('table', {
	mediumint: mediumint(),
	mediumint2: mediumint({ unsigned: true })
});
```

```sql
CREATE TABLE `table` (
	`mediumint` mediumint,
	`mediumint2` mediumint unsigned
);
```
</Section>

### bigint

An `8`-byte integer with a range of `-2^63` to `2^63-1` signed, or `0` to `2^64-1` unsigned

For more info please refer to the official MySQL **[docs.](https://dev.mysql.com/doc/refman/8.0/en/integer-types.html)**

<Section>
```typescript
import { bigint, mysqlTable } from "drizzle-orm/mysql-core";

export const table = mysqlTable('table', {
	bigint: bigint({ mode: 'number' }),
	bigintUnsigned: bigint({ mode: 'number', unsigned: true })
});

bigint("...", { mode: 'number' | 'bigint' | 'string' });

// You can also specify unsigned option for bigint
bigint("...", { mode: 'number' | 'bigint' | 'string', unsigned: true });
```

```sql
CREATE TABLE `table` (
	`bigint` bigint,
	`bigintUnsigned` bigint unsigned
);
```
</Section>

We've omitted config of `M` in `bigint(M)`, since it indicates the display width of the numeric type 

## ---

### real

A floating-point number

For more info please refer to the official MySQL **[docs.](https://dev.mysql.com/doc/refman/8.0/en/floating-point-types.html)**

<Section>
```typescript
import { real, mysqlTable } from "drizzle-orm/mysql-core";

export const table = mysqlTable('table', {
	real: real()
});
```

```sql
CREATE TABLE `table` (
	`real` real
);
```
</Section>

<Section>
```typescript
import { real, mysqlTable } from "drizzle-orm/mysql-core";

export const table = mysqlTable('table', {
	realPrecision: real({ precision: 1 }),
	realPrecisionScale: real({ precision: 1, scale: 1 }),
});
```

```sql
CREATE TABLE `table` (
	`realPrecision` real(1),
	`realPrecisionScale` real(1, 1)
);
```
</Section>

### decimal

An exact fixed-point number. `DECIMAL(M, D)` stores up to `M` total digits with `D` digits after the decimal point. Maximum precision is `65` digits

For more info please refer to the official MySQL **[docs.](https://dev.mysql.com/doc/refman/8.0/en/fixed-point-types.html)**

<Section>
```typescript
import { decimal, mysqlTable } from "drizzle-orm/mysql-core";

export const table = mysqlTable('table', {
	decimal: decimal(),
	decimalNum: decimal({ precision: 30, mode: 'number' }),
	decimalBig: decimal({ precision: 30, mode: 'bigint' }),
	decimal2: decimal({ precision: 30, scale: 10 }),
});
```

```sql
CREATE TABLE `table` (
	`decimal` decimal,
	`decimalNum` decimal(30),
	`decimalBig` decimal(30),
	`decimal2` decimal(30,10)
);
```
</Section>

### double

An `8`-byte double-precision floating-point number representing approximate numeric data values

For more info please refer to the official MySQL **[docs.](https://dev.mysql.com/doc/refman/8.0/en/floating-point-types.html)**

<Section>
```typescript
import { double, mysqlTable } from "drizzle-orm/mysql-core";

export const table = mysqlTable('table', {
	double: double()
});
```

```sql
CREATE TABLE `table` (
	`double` double
);
```
</Section>

<Section>
```typescript
import { double, mysqlTable } from "drizzle-orm/mysql-core";

export const table = mysqlTable('table', {
	doublePrecision: double({ precision: 1 }),
	doublePrecisionScale: double({ precision: 1, scale: 1 })
});
```

```sql
CREATE TABLE `table` (
	`doublePrecision` double(1),
	`doublePrecisionScale` double(1,1)
);
```
</Section>

### float

A `4`-byte single-precision floating-point number representing approximate numeric data values

For more info please refer to the official MySQL **[docs.](https://dev.mysql.com/doc/refman/8.0/en/floating-point-types.html)**

<Section>
```typescript
import { float, mysqlTable } from "drizzle-orm/mysql-core";

export const table = mysqlTable('table', {
	float: float()
});
```

```sql
CREATE TABLE `table` (
	`float` float
);
```
</Section>

## ---

### serial

<Section>

`SERIAL` is an alias for `BIGINT UNSIGNED NOT NULL AUTO_INCREMENT UNIQUE`.

For more info please refer to the official MySQL **[docs.](https://dev.mysql.com/doc/refman/8.0/en/numeric-type-syntax.html)**

```typescript
import { serial, mysqlTable } from "drizzle-orm/mysql-core";

export const table = mysqlTable('table', {
	serial: serial()
});
```

```sql
CREATE TABLE `table` (
	`serial` serial
);
```
</Section>

## ---

### binary
`BINARY(M)` stores a fixed-length byte string of exactly M bytes (If omitted, M defaults to 1).  
On insert, shorter values are right-padded with `0x00` bytes to reach M bytes; on retrieval, no padding is stripped.
All bytes are significant in comparisons, including `ORDER BY` and `DISTINCT` operations

For more info please refer to the official MySQL **[docs.](https://dev.mysql.com/doc/refman/8.0/en/binary-varbinary.html)**
<Section>
```typescript
import { binary, mysqlTable } from "drizzle-orm/mysql-core";

export const table = mysqlTable('table', {
	binary: binary(),
	binary2: binary({ length: 10 }),
});
```

```sql
CREATE TABLE `table` (
	`binary` binary,
	`binary2` binary(10)
);
```
</Section>

### varbinary
`VARBINARY(M)` stores a variable-length byte string of up to M bytes (M as required).  
For `VARBINARY`, there is no padding for inserts and no bytes are stripped for retrievals.
All bytes are significant in comparisons, including `ORDER BY` and `DISTINCT` operations

For more info please refer to the official MySQL **[docs.](https://dev.mysql.com/doc/refman/8.0/en/binary-varbinary.html)**
<Section>
```typescript
import { varbinary, mysqlTable } from "drizzle-orm/mysql-core";

export const table = mysqlTable('table', {
	varbinary: varbinary({ length: 2 }),
});
```

```sql
CREATE TABLE `table` (
	`varbinary` varbinary(2)
);
```
</Section>

## ---

### blob

A `BLOB` is a binary large object that can hold a variable amount of data with a maximum length of `65,535` bytes (`64` KB)

For more info please refer to the official MySQL **[docs.](https://dev.mysql.com/doc/refman/8.0/en/blob.html)**
<Section>
```typescript
import { blob, mysqlTable } from "drizzle-orm/mysql-core";

export const table = mysqlTable('table', {
	blob: blob()
});
```

```sql
CREATE TABLE `table` (
	`blob` blob
);
```
</Section>

<Section>
You can specify either `buffer` or `string` mode:
```typescript
// will be inferred as `Buffer`
blob: blob({ mode: "buffer" }),

// will be inferred as `string`
blob: blob({ mode: "string" }),
```
</Section>

> The `buffer` mode is the default way to work with blobs.
> Drizzle will represent the blob value as a `Buffer` instance

> The `string` mode represents blob values as UTF-8 encoded strings,
> which can be useful when storing text data in blob columns


### tinyblob

A `BLOB` column with a maximum length of `255` bytes

For more info please refer to the official MySQL **[docs.](https://dev.mysql.com/doc/refman/8.0/en/blob.html)**
<Section>
```typescript
import { tinyblob, mysqlTable } from "drizzle-orm/mysql-core";

export const table = mysqlTable('table', {
	tinyblob: tinyblob()
});
```

```sql
CREATE TABLE `table` (
	`tinyblob` tinyblob
);
```
</Section>

<Section>
You can specify either `buffer` or `string` mode:
```typescript
// will be inferred as `Buffer`
tinyblob: tinyblob({ mode: "buffer" }),

// will be inferred as `string`
tinyblob: tinyblob({ mode: "string" }),
```
</Section>

> The `buffer` mode is the default way to work with blobs.
> Drizzle will represent the blob value as a `Buffer` instance

> The `string` mode represents blob values as UTF-8 encoded strings,
> which can be useful when storing text data in blob columns

### mediumblob

A `BLOB` column with a maximum length of `16,777,215` bytes (`16` MB)

For more info please refer to the official MySQL **[docs.](https://dev.mysql.com/doc/refman/8.0/en/blob.html)**
<Section>
```typescript
import { mediumblob, mysqlTable } from "drizzle-orm/mysql-core";

export const table = mysqlTable('table', {
	mediumblob: mediumblob()
});
```

```sql
CREATE TABLE `table` (
	`mediumblob` mediumblob
);
```
</Section>

<Section>
You can specify either `buffer` or `string` mode:
```typescript
// will be inferred as `Buffer`
mediumblob: mediumblob({ mode: "buffer" }),

// will be inferred as `string`
mediumblob: mediumblob({ mode: "string" }),
```
</Section>

> The `buffer` mode is the default way to work with blobs.
> Drizzle will represent the blob value as a `Buffer` instance

> The `string` mode represents blob values as UTF-8 encoded strings,
> which can be useful when storing text data in blob columns


### longblob

A `BLOB` column with a maximum length of `4,294,967,295` bytes (`4` GB)

For more info please refer to the official MySQL **[docs.](https://dev.mysql.com/doc/refman/8.0/en/blob.html)**
<Section>
```typescript
import { longblob, mysqlTable } from "drizzle-orm/mysql-core";

export const table = mysqlTable('table', {
	longblob: longblob()
});
```

```sql
CREATE TABLE `table` (
	`longblob` longblob
);
```
</Section>

<Section>
You can specify either `buffer` or `string` mode:
```typescript
// will be inferred as `Buffer`
longblob: longblob({ mode: "buffer" }),

// will be inferred as `string`
longblob: longblob({ mode: "string" }),
```
</Section>

> The `buffer` mode is the default way to work with blobs.
> Drizzle will represent the blob value as a `Buffer` instance

> The `string` mode represents blob values as UTF-8 encoded strings,
> which can be useful when storing text data in blob columns

## ---

### char

The length of a `CHAR(M)` column is fixed to the length that you declare when you create the table. `M` can be any value from `0` to `255`, default is `1`
When `CHAR` values are stored, they are right-padded with spaces to the specified length. When `CHAR` values are retrieved, trailing spaces are removed unless the [PAD_CHAR_TO_FULL_LENGTH](https://dev.mysql.com/doc/refman/9.7/en/sql-mode.html#sqlmode_pad_char_to_full_length) SQL mode is enabled.

For more info please refer to the official MySQL **[docs.](https://dev.mysql.com/doc/refman/8.0/en/char.html)**

You can define `{ enum: ["value1", "value2"] }` config to infer insert and select types, it won't check runtime values.

<Section>
```typescript
import { char, mysqlTable } from "drizzle-orm/mysql-core";

export const table = mysqlTable('table', {
	char: char(),
});

// will be inferred as char: "value1" | "value2" | null
char: char({ enum: ["value1", "value2"] })
```

```sql
CREATE TABLE `table` (
	`char` char
);
```
</Section>

### varchar

Values in `VARCHAR` columns are variable-length strings.  
`VARCHAR(M)` stores up to `M` characters, where `M` ranges from `0` to `65,535`
`VARCHAR` values are not padded when they are stored. Trailing spaces are retained when values are stored and retrieved, in conformance with standard SQL

For more info please refer to the official MySQL **[docs.](https://dev.mysql.com/doc/refman/8.0/en/char.html)**

You can define `{ enum: ["value1", "value2"] }` config to infer `insert` and `select` types, it **won't** check runtime values.
<Section>
```typescript
import { varchar, mysqlTable } from "drizzle-orm/mysql-core";

export const table = mysqlTable('table', {
	varchar: varchar({ length: 2 }),
});

// will be inferred as text: "value1" | "value2" | null
varchar: varchar({ length: 6, enum: ["value1", "value2"] })
```

```sql
CREATE TABLE `table` (
	`varchar` varchar(2)
);
```
</Section>

### text

A `TEXT` column with a maximum length of `65,535` characters (`64` KB)

For more info please refer to the official MySQL **[docs.](https://dev.mysql.com/doc/refman/8.0/en/blob.html)**

You can define `{ enum: ["value1", "value2"] }` config to infer `insert` and `select` types, it **won't** check runtime values.

<Section>
```typescript
import { text, mysqlTable } from "drizzle-orm/mysql-core";

export const table = mysqlTable('table', {
	text: text(),
});

// will be inferred as text: "value1" | "value2" | null
text: text({ enum: ["value1", "value2"] });
```

```sql
CREATE TABLE `table` (
	`text` text
);
```
</Section>

### tinytext

A `TEXT` column with a maximum length of `255` characters

For more info please refer to the official MySQL **[docs.](https://dev.mysql.com/doc/refman/8.0/en/blob.html)**

You can define `{ enum: ["value1", "value2"] }` config to infer `insert` and `select` types, it **won't** check runtime values.

<Section>
```typescript
import { tinytext, mysqlTable } from "drizzle-orm/mysql-core";

export const table = mysqlTable('table', {
	tinytext: tinytext(),
});

// will be inferred as tinytext: "value1" | "value2" | null
tinytext: tinytext({ enum: ["value1", "value2"] });
```

```sql
CREATE TABLE `table` (
	`tinytext` tinytext
);
```
</Section>

### mediumtext

A `TEXT` column with a maximum length of `16,777,215` characters (`16` MB)

For more info please refer to the official MySQL **[docs.](https://dev.mysql.com/doc/refman/8.0/en/blob.html)**

You can define `{ enum: ["value1", "value2"] }` config to infer `insert` and `select` types, it **won't** check runtime values.

<Section>
```typescript
import { mediumtext, mysqlTable } from "drizzle-orm/mysql-core";

export const table = mysqlTable('table', {
	mediumtext: mediumtext(),
});

// will be inferred as mediumtext: "value1" | "value2" | null
mediumtext: mediumtext({ enum: ["value1", "value2"] });
```

```sql
CREATE TABLE `table` (
	`mediumtext` mediumtext
);
```
</Section>

### longtext

A `TEXT` column with a maximum length of `4,294,967,295` characters (`4` GB)

For more info please refer to the official MySQL **[docs.](https://dev.mysql.com/doc/refman/8.0/en/blob.html)**

You can define `{ enum: ["value1", "value2"] }` config to infer `insert` and `select` types, it **won't** check runtime values.

<Section>
```typescript
import { longtext, mysqlTable } from "drizzle-orm/mysql-core";

export const table = mysqlTable('table', {
	longtext: longtext(),
});

// will be inferred as longtext: "value1" | "value2" | null
longtext: longtext({ enum: ["value1", "value2"] });
```

```sql
CREATE TABLE `table` (
	`longtext` longtext
);
```
</Section>

## ---

### boolean

`BOOLEAN` is a synonym for `TINYINT(1)`. A value of `0` is considered false, non-zero values are considered true

For more info please refer to the official MySQL **[docs.](https://dev.mysql.com/doc/refman/8.0/en/numeric-type-syntax.html)**

<Section>
```typescript
import { boolean, mysqlTable } from "drizzle-orm/mysql-core";

export const table = mysqlTable('table', {
	boolean: boolean(),
});
```

```sql
CREATE TABLE `table` (
	`boolean` boolean
);
```
</Section>

## ---

### date

A date value in `'YYYY-MM-DD'` format, with a range of `'1000-01-01'` to `'9999-12-31'`

For more info please refer to the official MySQL **[docs.](https://dev.mysql.com/doc/refman/8.0/en/datetime.html)**

<Section>
```typescript
import { date, mysqlTable } from "drizzle-orm/mysql-core";

export const table = mysqlTable('table', {
	date: date(),
});
```

```sql
CREATE TABLE `table` (
	`date` date
);
```
</Section>

You can specify either `date` or `string` infer modes:
```typescript
// will infer as date
date: date({ mode: "date" }),

// will infer as string
date: date({ mode: "string" }),
```

### datetime

A date and time value in `'YYYY-MM-DD hh:mm:ss'` format, with a range of `'1000-01-01 00:00:00'` to `'9999-12-31 23:59:59'`. Supports fractional seconds up to `6` digits

For more info please refer to the official MySQL **[docs.](https://dev.mysql.com/doc/refman/8.0/en/datetime.html)**

<Section>
```typescript
import { datetime, mysqlTable } from "drizzle-orm/mysql-core";

export const table = mysqlTable('table', {
	datetime: datetime(),
});

datetime('...', { mode: 'date' | "string"}),
datetime('...', { fsp : 0..6}),
```

```sql
CREATE TABLE `table` (
	`datetime` datetime
);
```
</Section>

<Section>
```typescript
import { datetime, mysqlTable } from "drizzle-orm/mysql-core";

export const table = mysqlTable('table', {
	datetime: datetime({ mode: 'date', fsp: 6 }),
});
```

```sql
CREATE TABLE `table` (
	`datetime` datetime(6)
);
```
</Section>

### time 

A time value in `'hh:mm:ss'` format, with a range of `'-838:59:59'` to `'838:59:59'`. Can represent time of day or elapsed time. Supports fractional seconds up to `6` digits

For more info please refer to the official MySQL **[docs.](https://dev.mysql.com/doc/refman/8.0/en/time.html)**

<Section>
```typescript
import { time, mysqlTable } from "drizzle-orm/mysql-core";

export const table = mysqlTable('table', {
	time: time(),
	timefsp: time({ fsp: 6 }),
});
	
time('...', { fsp: 0..6 }),
```

```sql
CREATE TABLE `table` (
	`time` time,
	`timefsp` time(6)
);
```
</Section>

### year

A `1`-byte type for year values in `YYYY` format, with a range of `1901` to `2155` and `0000`

For more info please refer to the official MySQL **[docs.](https://dev.mysql.com/doc/refman/8.0/en/year.html)**

<Section>
```typescript
import { year, mysqlTable } from "drizzle-orm/mysql-core";

export const table = mysqlTable('table', {
	year: year(),
});
```

```sql
CREATE TABLE `table` (
	`year` year
);
```
</Section>

### timestamp

A date and time value in `'YYYY-MM-DD hh:mm:ss'` format, with a range of `'1970-01-01 00:00:01'` UTC to `'2038-01-19 03:14:07'` UTC. MySQL converts `TIMESTAMP` values from the current time zone to UTC for storage, and back from UTC to the current time zone for retrieval. Supports fractional seconds up to `6` digits

For more info please refer to the official MySQL **[docs.](https://dev.mysql.com/doc/refman/8.0/en/datetime.html)**

<Section>
```typescript
import { timestamp, mysqlTable } from "drizzle-orm/mysql-core";

export const table = mysqlTable('table', {
	timestamp: timestamp(),
});

timestamp('...', { mode: 'date' | "string"}),
timestamp('...', { fsp : 0..6}),
```

```sql
CREATE TABLE `table` (
	`timestamp` timestamp
);
```
</Section>

<Section>
```typescript
import { timestamp, mysqlTable } from "drizzle-orm/mysql-core";

export const table = mysqlTable('table', {
	timestamp: timestamp({ mode: 'date', fsp: 6 }),
});
```

```sql
CREATE TABLE `table` (
	`timestamp` timestamp(6)
);
```
</Section>

<Section>
```typescript
import { timestamp, mysqlTable } from "drizzle-orm/mysql-core";

export const table = mysqlTable('table', {
	timestamp: timestamp().defaultNow(),
});
```

```sql
CREATE TABLE `table` (
	`timestamp` timestamp DEFAULT (now())
);
```
</Section>

## ---

### json

A native `JSON` data type that enables efficient access to data in JSON documents. JSON documents are automatically validated and stored in an optimized binary format that permits quick read access to document elements

For more info please refer to the official MySQL **[docs.](https://dev.mysql.com/doc/refman/8.0/en/json.html)**

<Section>
```typescript
import { json, mysqlTable } from "drizzle-orm/mysql-core";

export const table = mysqlTable('table', {
	json: json(),
});

```

```sql
CREATE TABLE `table` (
	`json` json
);
```
</Section>

You can specify `.$type<..>()` for json object inference, it **won't** check runtime values. 
It provides compile time protection for default values, insert and select schemas.
```typescript
// will be inferred as { foo: string }
json: json().$type<{ foo: string }>();

// will be inferred as string[]
json: json().$type<string[]>();

// won't compile
json: json().$type<string[]>().default({});
```

## ---

### enum

A string object with a value chosen from a list of permitted values that are enumerated at table creation time.

For more info please refer to the official MySQL **[docs.](https://dev.mysql.com/doc/refman/8.0/en/enum.html)**

<Section>
```typescript
import { mysqlEnum, mysqlTable } from "drizzle-orm/mysql-core";

export const table = mysqlTable('table', {
	popularity: mysqlEnum(['unknown', 'known', 'popular']),
});
```

```sql
CREATE TABLE `table` (
	`popularity` enum('unknown','known','popular')
);
```
</Section>

## ---

### Customizing data type

Every column builder has a `.$type()` method, which allows you to customize the data type of the column. This is useful, for example, with unknown or branded types.

```ts
import { int, json, mysqlTable } from "drizzle-orm/mysql-core";

type UserId = number & { __brand: "user_id" };
type Data = {
  foo: string;
  bar: number;
};

export const users = mysqlTable("users", {
  id: int().$type<UserId>().primaryKey(),
  jsonField: json().$type<Data>(),
});
```

### Not null
`NOT NULL` constraint dictates that the associated column may not contain a `NULL` value.

<Section>
```typescript
import { int, mysqlTable } from "drizzle-orm/mysql-core";

export const table = mysqlTable('table', {
	int: int().notNull(),
});
```

```sql
CREATE TABLE `table` (
	`int` int NOT NULL
);
```
</Section>

### Default value

The `DEFAULT` clause specifies a default value to use for the column if no value
is explicitly provided by the user when doing an `INSERT`.
If there is no explicit `DEFAULT` clause attached to a column definition,
then the default value of the column is `NULL`.

An explicit `DEFAULT` clause may specify that the default value is `NULL`,
a string constant, a blob constant, a signed-number, or any constant expression enclosed in parentheses.

<Section>
```typescript
import { sql } from "drizzle-orm";
import { int, mysqlTable } from "drizzle-orm/mysql-core";

export const table = mysqlTable("table", {
  int: int().default(3),
  int2: int().default(sql`3`),
});
```

```sql
CREATE TABLE `table` (
	`int` int DEFAULT 3,
	`int2` int DEFAULT (3)
);
```
</Section>

When using `$default()` or `$defaultFn()`, which are simply different aliases for the same function, 
you can generate defaults at runtime and use these values in all insert queries. 
These functions can assist you in utilizing various implementations such as `uuid`, `cuid`, `cuid2`, and many more.

<Callout type="info" emoji="ℹ️">
	Note: This value does not affect the `drizzle-kit` behavior, it is only used at runtime in `drizzle-orm`
</Callout>

```ts
import { varchar, mysqlTable } from "drizzle-orm/mysql-core";
import { createId } from '@paralleldrive/cuid2';

export const table = mysqlTable('table', {
	id: varchar({ length: 128 }).$defaultFn(() => createId()),
});
```

When using `$onUpdate()` or `$onUpdateFn()`, which are simply different aliases for the same function, 
you can generate defaults at runtime and use these values in all update queries. 

Adds a dynamic update value to the column. The function will be called when the row is updated, 
and the returned value will be used as the column value if none is provided.
If no default (or $defaultFn) value is provided, the function will be called
when the row is inserted as well, and the returned value will be used as the column value.

<Callout type="info" emoji="ℹ️">
	Note: This value does not affect the `drizzle-kit` behavior, it is only used at runtime in `drizzle-orm`
</Callout>

```ts
import { text, mysqlTable } from "drizzle-orm/mysql-core";

export const table = mysqlTable('table', {
    alwaysNull: text().$type<string | null>().$onUpdate(() => null),
});
```

### Primary key 

<Section>
```typescript
import { int, mysqlTable } from "drizzle-orm/mysql-core";

export const table = mysqlTable('table', {
	int: int().primaryKey(),
});
```

```sql
CREATE TABLE `table` (
	`int` int PRIMARY KEY NOT NULL
);
```
</Section>

### Auto increment

<Section>
```typescript
import { int, mysqlTable } from "drizzle-orm/mysql-core";

export const table = mysqlTable('table', {
	int: int().autoincrement(),
});
```

```sql
CREATE TABLE `table` (
	`int` int AUTO_INCREMENT
);
```
</Section>


Source: https://orm.drizzle.team/docs/mysql/connect-appwrite-mysql

import Npm from "@mdx/Npm.astro";
import Callout from "@mdx/Callout.astro";
import Tabs from "@mdx/Tabs.astro";
import Tab from "@mdx/Tab.astro";
import AnchorCards from "@mdx/AnchorCards.astro";
import WhatsNextMySQL from "@mdx/WhatsNextMySQL.astro";
import Prerequisites from "@mdx/Prerequisites.astro";
import CodeTabs from "@mdx/CodeTabs.astro";

# Drizzle \<\> Appwrite MySQL

<Prerequisites>
- Database [connection basics](/docs/mysql/connect-overview) with Drizzle
- Appwrite native MySQL database - [website](https://appwrite.io) & [docs](https://appwrite.io/docs/products/databases/mysql)
- Appwrite MySQL connections - [docs](https://appwrite.io/docs/products/databases/mysql/connections)
- Drizzle MySQL drivers - [docs](/docs/mysql/get-started-mysql)
</Prerequisites>

Appwrite offers dedicated, native MySQL databases that you connect to directly over TLS. There is no Appwrite-specific driver or abstraction layer, so you can use Drizzle with the [`mysql2`](https://github.com/sidorares/node-mysql2) driver through the `drizzle-orm/mysql2` package, the same way you would with any MySQL server.

To get your connection string, open your database in the Appwrite Console and click **Credentials**, or fetch it from the Appwrite API with `mysql.get()`. The username is `admin.<hash>`, where the hash matches the one in the hostname, and the database name is always `default`. Appwrite's proxy routes your connection by this username, so always use the full value from the connection string.

```env
DATABASE_URL="mysql://admin.<hash>:<password>@db-<hash>.<region>.appwrite.center:3306/default?ssl=true"
```

#### Step 1 - Install packages
<Npm>
 drizzle-orm@rc mysql2
 -D drizzle-kit@rc
</Npm>

#### Step 2 - Initialize the driver and make a query
<CodeTabs items={['mysql2', 'mysql2 with config']}>
```typescript copy
import { drizzle } from "drizzle-orm/mysql2";

const db = drizzle(process.env.DATABASE_URL);

const response = await db.select().from(...)
```
```typescript copy
import { drizzle } from "drizzle-orm/mysql2";

// You can specify any property from the mysql2 connection options
const db = drizzle({ connection: { uri: process.env.DATABASE_URL, ssl: { rejectUnauthorized: true } } });

const response = await db.select().from(...)
```
</CodeTabs>

If you need to provide your existing driver:

<CodeTabs items={['Client connection', 'Pool connection']}>
```typescript copy
import { drizzle } from "drizzle-orm/mysql2";
import mysql from "mysql2/promise";

const connection = await mysql.createConnection(process.env.DATABASE_URL);

const db = drizzle({ client: connection });
```
```typescript copy
import { drizzle } from "drizzle-orm/mysql2";
import mysql from "mysql2/promise";

const poolConnection = mysql.createPool({
  uri: process.env.DATABASE_URL,
});

const db = drizzle({ client: poolConnection });
```
</CodeTabs>

<Callout type="warning" emoji="⚙️">
Connections on Appwrite Cloud are encrypted with TLS. If your runtime or `mysql2` configuration does not infer TLS from the connection string, pass `ssl: { rejectUnauthorized: true }` in the connection options.

For the built in `migrate` function with DDL migrations we and drivers strongly encourage you to use a single `client` connection.
</Callout>

#### Connection pooling for serverless

Appwrite runs a [connection pooler](https://appwrite.io/docs/products/databases/mysql/connection-pooling) on port `6033` of the same hostname. In serverless and edge environments, route your application traffic through the pooler so short-lived instances don't exhaust the engine's connection limit, and keep Drizzle Kit pointed at the direct engine port `3306`, because migrations issue DDL that needs a session-level connection.

```env
# Runtime: pooled, transaction mode
DATABASE_URL="mysql://admin.<hash>:<password>@db-<hash>.<region>.appwrite.center:6033/default?ssl=true"

# Migrations & introspection: direct connection to the engine
DIRECT_URL="mysql://admin.<hash>:<password>@db-<hash>.<region>.appwrite.center:3306/default?ssl=true"
```

```typescript copy filename="drizzle.config.ts"
import { defineConfig } from 'drizzle-kit';

export default defineConfig({
  dialect: 'mysql',
  schema: './src/schema.ts',
  out: './drizzle',
  dbCredentials: {
    url: process.env.DIRECT_URL!,
  },
});
```

The pooler defaults to transaction mode, which does not keep a backend connection across statements. Drizzle's regular query builder sends text queries and works with transaction pooling, but session-level features such as explicit prepared queries, user variables and temporary tables need the direct port or a session-mode pooler.

#### What's next?

<WhatsNextMySQL/>


Source: https://orm.drizzle.team/docs/mysql/connect-aws-data-api-mysql

import Callout from '@mdx/Callout.astro';


# Drizzle \<\> AWS Data API MySQL

<Callout>
Currently AWS Data API for MySQL is not implemented in Drizzle ORM
</Callout>


Source: https://orm.drizzle.team/docs/mysql/connect-bun-sql

import Npm from "@mdx/Npm.astro";
import Callout from '@mdx/Callout.astro';
import AnchorCards from '@mdx/AnchorCards.astro';
import Steps from '@mdx/Steps.astro';
import WhatsNextMySQL from "@mdx/WhatsNextMySQL.astro";
import Prerequisites from "@mdx/Prerequisites.astro";
import CodeTabs from "@mdx/CodeTabs.astro";

# Drizzle \<\> Bun SQL

<Prerequisites>
- Database [connection basics](/docs/connect-overview) with Drizzle
- Bun - [website](https://bun.sh/docs)
- Bun SQL - native bindings for working with MySQL databases - [read here](https://bun.sh/docs/api/sql)
</Prerequisites>

According to the **[official website](https://bun.sh/)**, Bun is a fast all-in-one JavaScript runtime. 

Drizzle ORM natively supports **[`bun sql`](https://bun.sh/docs/api/sql)** module and it's crazy fast 🚀  

#### Step 1 - Install packages
<Npm>
 drizzle-orm@rc
 -D drizzle-kit@rc
</Npm>

#### Step 2 - Initialize the driver and make a query
```typescript copy
import 'dotenv/config';
import { drizzle } from 'drizzle-orm/bun-sql/mysql';

const db = drizzle(process.env.DATABASE_URL);

const result = await db.select().from(...);
```

If you need to provide your existing driver:
```typescript copy
import 'dotenv/config';
import { drizzle } from 'drizzle-orm/bun-sql/mysql';
import { SQL } from 'bun';

const client = new SQL(process.env.DATABASE_URL!);
const db = drizzle({ client });
```

#### What's next?

<WhatsNextMySQL/>


Source: https://orm.drizzle.team/docs/mysql/connect-drizzle-proxy

import Npm from "@mdx/Npm.astro";
import Callout from '@mdx/Callout.astro';
import Steps from '@mdx/Steps.astro';
import AnchorCards from '@mdx/AnchorCards.astro';
import Prerequisites from "@mdx/Prerequisites.astro";
import Section from "@mdx/Section.astro";

# Drizzle HTTP proxy

<Prerequisites>
- Database [connection basics](/docs/mysql/connect-overview) with Drizzle
</Prerequisites>

How an HTTP Proxy works and why you might need it

Drizzle Proxy is used when you need to implement your own driver communication with the database. 
It can be used in several cases, such as adding custom logic at the query stage with existing drivers. 
The most common use is with an HTTP driver, which sends queries to your server with the database, executes the query 
on your database, and responds with raw data that Drizzle ORM can then map to results

<Callout collapsed="How it works under the hood?">
```                                  
┌───────────────────────────┐                 ┌─────────────────────────────┐              
│       Drizzle ORM         │                 │  HTTP Server with Database  │             
└─┬─────────────────────────┘                 └─────────────────────────┬───┘             
  │                                                ^                    │
  │-- 1. Build query         2. Send built query --│                    │
  │                                                │                    │
  │              ┌───────────────────────────┐     │                    │
  └─────────────>│                           │─────┘                    │ 
                 │      HTTP Proxy Driver    │                          │
  ┌──────────────│                           │<─────────────┬───────────┘
  │              └───────────────────────────┘              │
  │                                                  3. Execute a query + send raw results back
  │-- 4. Map data and return        
  │                   
  v
```
</Callout>

Drizzle ORM also supports simply using asynchronous callback function for executing SQL.

- `sql` is a query string with placeholders.
- `params` is an array of parameters.
- One of the following values will set for `method` depending on the SQL statement - `all`, `execute`.

Drizzle always waits for `{rows: string[][]}` or `{rows: string[]}` for the return value.

- When the `method` is `execute`, you should return a value as `{rows: string[]}`.
- Otherwise, you should return `{rows: string[][]}`.

<br/>

<Section>
```typescript copy
// Example of driver implementation
import { drizzle } from 'drizzle-orm/mysql-proxy';
import axios from "axios";

const db = drizzle(async (sql, params, method) => {
  try {
    const rows = await axios.post('http://localhost:3000/query', { sql, params, method });

    return { rows: rows.data };
  } catch (e: any) {
    console.error('Error from mysql proxy server: ', e.response.data)
    return { rows: [] };
  }
});
```
```ts
// Example of server implementation
import * as mysql from 'mysql2/promise';
import express from 'express';

const app = express();

app.use(express.json());
const port = 3000;

const main = async () => {
    const connection = await mysql.createConnection('mysql://root:mysql@127.0.0.1:5432/drizzle');

    app.post('/query', async (req, res) => {
      const { sql, params, method } = req.body;

      // prevent multiple queries
      const sqlBody = sql.replace(/;/g, '');

      try {
            const result = await connection.query({
                sql: sqlBody,
                values: params,
                rowsAsArray: method === 'all',
                typeCast: function(field: any, next: any) {
                    if (field.type === 'TIMESTAMP' || field.type === 'DATETIME' || field.type === 'DATE') {
                        return field.string();
                    }
                    return next();
                },
            });
      } catch (e: any) {
        res.status(500).json({ error: e });
      }

      if (method === 'all') {
        res.send(result[0]);
      } else if (method === 'execute') {
        res.send(result);
      }
      res.status(500).json({ error: 'Unknown method value' });
    });

    app.listen(port, () => {
      console.log(`Example app listening on port ${port}`);
    });
}

main();
```
</Section>


Source: https://orm.drizzle.team/docs/mysql/connect-overview

# Database connection with Drizzle

Use these MySQL drivers and providers with Drizzle ORM.

## MySQL connection docs

- [MySQL](/docs/mysql/get-started-mysql)
- [PlanetScale MySQL](/docs/mysql/connect-planetscale)
- [TiDB](/docs/mysql/connect-tidb)
- [Appwrite MySQL](/docs/mysql/connect-appwrite-mysql)
- [AWS Data API MySQL](/docs/mysql/connect-aws-data-api-mysql)
- [Bun SQL](/docs/mysql/connect-bun-sql)
- [Drizzle HTTP proxy](/docs/mysql/connect-drizzle-proxy)


Source: https://orm.drizzle.team/docs/mysql/connect-planetscale

import Npm from "@mdx/Npm.astro";
import Callout from "@mdx/Callout.astro";
import Tabs from "@mdx/Tabs.astro";
import Tab from "@mdx/Tab.astro";
import AnchorCards from "@mdx/AnchorCards.astro";
import WhatsNextMySQL from "@mdx/WhatsNextMySQL.astro";
import Prerequisites from "@mdx/Prerequisites.astro";
import CodeTabs from "@mdx/CodeTabs.astro";

# Drizzle \<\> PlanetScale MySQL

<Prerequisites>

- Database [connection basics](/docs/mysql/connect-overview) with Drizzle
- PlanetScale database - [website](https://planetscale.com/docs)
- PlanetScale http driver - [GitHub](https://github.com/planetscale/database-js)
- Drizzle MySQL drivers - [docs](/docs/mysql/get-started-mysql)

</Prerequisites>

PlanetScale offers both MySQL (Vitess) and PostgreSQL databases. This page covers connecting to PlanetScale MySQL.

For PlanetScale Postgres, see the [PlanetScale Postgres connection guide](/docs/connect-planetscale-postgres).

With Drizzle ORM you can access PlanetScale MySQL over http
through their official **[`database-js`](https://github.com/planetscale/database-js)**
driver from serverless and serverfull environments with our `drizzle-orm/planetscale-serverless` package.

You can also access PlanetScale MySQL through TCP with `mysql2` driver — **[see here.](/docs/mysql/get-started-mysql)**

#### Step 1 - Install packages

<Npm>
 drizzle-orm@rc @planetscale/database
 -D drizzle-kit@rc
</Npm>

#### Step 2 - Initialize the driver and make a query

```typescript copy"
import { drizzle } from "drizzle-orm/planetscale-serverless";

const db = drizzle({ connection: {
  host: process.env["DATABASE_HOST"],
  username: process.env["DATABASE_USERNAME"],
  password: process.env["DATABASE_PASSWORD"],
}});

const response = await db.select().from(...)
```

If you need to provide your existing driver

```typescript copy"
import { drizzle } from "drizzle-orm/planetscale-serverless";
import { Client } from "@planetscale/database";

const client = new Client({
  host: process.env["DATABASE_HOST"],
  username: process.env["DATABASE_USERNAME"],
  password: process.env["DATABASE_PASSWORD"],
});

const db = drizzle({ client });
```

Make sure to checkout the PlanetScale official **[MySQL courses](https://planetscale.com/courses/mysql-for-developers)**,
we think they're outstanding 🙌

#### What's next?

<WhatsNextMySQL />


Source: https://orm.drizzle.team/docs/mysql/connect-tidb

import Npm from '@mdx/Npm.astro';
import Callout from '@mdx/Callout.astro';
import Tabs from '@mdx/Tabs.astro';
import Tab from '@mdx/Tab.astro';
import AnchorCards from '@mdx/AnchorCards.astro';
import WhatsNextMySQL from "@mdx/WhatsNextMySQL.astro";
import Prerequisites from "@mdx/Prerequisites.astro";
import CodeTabs from "@mdx/CodeTabs.astro";

# Drizzle \<\> TiDB Serverless

<Prerequisites>
- Database [connection basics](/docs/mysql/connect-overview) with Drizzle
- TiDB database - [website](https://docs.pingcap.com/)
- TiDB HTTP Driver - [website](https://docs.pingcap.com/developer/serverless-driver)
- Drizzle MySQL drivers - [docs](/docs/mysql/get-started-mysql)
</Prerequisites>

According to the **[official website](https://www.pingcap.com/tidb-serverless/)**, 
TiDB Serverless is a fully-managed, autonomous DBaaS with split-second cluster provisioning and consumption-based pricing.

<Callout type="info" emoji="ℹ️">
TiDB Serverless is compatible with MySQL, so you can use [MySQL connection guide](/docs/mysql/get-started-mysql) to connect to it.
</Callout>

TiDB Serverless provides an [HTTP driver](https://docs.pingcap.com/developer/serverless-driver/) for edge environments. It is natively supported by Drizzle ORM via `drizzle-orm/tidb-serverless` package.

#### Step 1 - Install packages
<Npm>
 drizzle-orm@rc @tidbcloud/serverless
 -D drizzle-kit@rc
</Npm>

#### Step 2 - Initialize the driver and make a query
```typescript copy filename="index.ts"
import { drizzle } from 'drizzle-orm/tidb-serverless';

const db = drizzle({ connection: { url: process.env.TIDB_URL }});

const response = await db.select().from(...)
```

If you need to provide your existing driver:
```typescript copy"
import { connect } from '@tidbcloud/serverless';
import { drizzle } from 'drizzle-orm/tidb-serverless';

const client = connect({ url: process.env.TIDB_URL });
const db = drizzle({ client });
```

#### What's next?

<WhatsNextMySQL/>


Source: https://orm.drizzle.team/docs/mysql/custom-types

# Custom types

Custom types let you define your own column types with custom SQL data types and JS/DB value transforms

MySQL exposes `customType` from `drizzle-orm/mysql-core`.

## Examples
The best way to see how `customType` definition is working is to check how existing data types could be defined using `customType` function from Drizzle ORM.

#### Int

```ts
import { customType, mysqlTable } from "drizzle-orm/mysql-core";

const customInt = customType<{ data: number }>({
  dataType() {
    return "int";
  },
});

export const users = mysqlTable("users", {
  id: customInt(),
});
```

#### Text
```ts
import { customType, mysqlTable } from 'drizzle-orm/mysql-core';

const customText = customType<{ data: string }>({
  dataType() {
    return 'text';
  },
});

export const users = mysqlTable("users", {
  name: customText(),
});
```

#### Timestamp
```ts
import { customType, mysqlTable } from "drizzle-orm/mysql-core";

const customTimestamp = customType<{
  data: Date;
  driverData: string;
  config: { fsp?: number };
  configRequired: true;
}>({
  dataType(config) {
    const precision = typeof config.fsp !== "undefined" ? ` (${config.fsp})` : "";
    return `timestamp${precision}`;
  },
  fromDriver(value: string): Date {
    return new Date(value);
  },
});

export const users = mysqlTable("users", {
  createdAt: customTimestamp("created_at", { fsp: 4 }),
});
```

Usage for all types will be same as defined functions in Drizzle ORM. For example:
```ts
const usersTable = mysqlTable("users", {
  id: customInt().primaryKey(),
  name: customText().notNull(),
  createdAt: customTimestamp("created_at", { fsp: 4 })
    .notNull()
    .default(sql`now()`),
});
```

### TS-doc for type definitions

You can check `ts-doc` for types, param definition and examples

```ts
interface CustomTypeValues {
  /**
   * Required type for custom column, that will infer proper type model
   *
   * Examples:
   *
   * If you want your column to be `string` type after selecting/or on inserting - use `data: string`. Like `text`, `varchar`
   *
   * If you want your column to be `number` type after selecting/or on inserting - use `data: number`. Like `integer`
   */
  data: unknown;
  /**
   * Type helper, that represents what type database driver is returning for specific database data type
   *
   * Needed only in case driver's output and input for type differ
   *
   * Defaults to {@link driverData}
   */
  driverOutput?: unknown;
  /**
   * Type helper, that represents what type database driver is accepting for specific database data type
   */
  driverData?: unknown;
  /**
   * Type helper, that represents what type field returns after being aggregated to JSON
   */
  jsonData?: unknown;
  /**
   * What config type should be used for {@link CustomTypeParams} `dataType` generation
   */
  config?: Record<string, any>;
  /**
   * Whether the config argument should be required or not
   * @default false
   */
  configRequired?: boolean;
  /**
   * If your custom data type should be notNull by default you can use `notNull: true`
   *
   * @example
   * const customSerial = customType<{ data: number, notNull: true, default: true }>({
   * 	  dataType() {
   * 	    return 'serial';
   *    },
   * });
   */
  notNull?: boolean;
  /**
   * If your custom data type has default you can use `default: true`
   *
   * @example
   * const customSerial = customType<{ data: number, notNull: true, default: true }>({
   * 	  dataType() {
   * 	    return 'serial';
   *    },
   * });
   */
  default?: boolean;
}
interface CustomTypeParams<T extends CustomTypeValues> {
  /**
   * Database data type string representation, that is used for migrations
   * @example
   * ```
   * `jsonb`, `text`
   * ```
   *
   * If database data type needs additional params you can use them from `config` param
   * @example
   * ```
   * `varchar(256)`, `numeric(2,3)`
   * ```
   *
   * To make `config` be of specific type please use config generic in {@link CustomTypeValues}
   *
   * @example
   * Usage example
   * ```
   *   dataType() {
   *     return 'boolean';
   *   },
   * ```
   * Or
   * ```
   *   dataType(config) {
   * 	   return typeof config.length !== 'undefined' ? `varchar(${config.length})` : `varchar`;
   * 	 }
   * ```
   */
  dataType: (config: T['config'] | (Equal<T['configRequired'], true> extends true ? never : undefined)) => string;
  /**
   * Optional mapping function, that is used to transform inputs from desired to be used in code format to one suitable for driver
   * @example
   * For example, when using jsonb we need to map JS/TS object to string before writing to database
   * ```
   * toDriver(value: TData): string {
   * 	 return JSON.stringify(value);
   * }
   * ```
   */
  toDriver?: (value: T['data']) => T['driverData'] | SQL;
  /**
   * Optional mapping function, that is used for transforming data returned by driver to desired column's output format
   * @example
   * For example, when using timestamp we need to map string Date representation to JS Date
   * ```
   * fromDriver(value: string): Date {
   * 	return new Date(value);
   * }
   * ```
   *
   * It'll cause the returned data to change from:
   * ```
   * {
   * 	customField: "2025-04-07 03:25:16.635";
   * }
   * ```
   * to:
   * ```
   * {
   * 	customField: new Date("2025-04-07 03:25:16.635");
   * }
   * ```
   */
  fromDriver?: (value: 'driverOutput' extends keyof T ? T['driverOutput'] : T['driverData']) => T['data'];
  /**
   * Optional mapping function, that is used for transforming data returned by transofmed to JSON in database data to desired format
   *
   * Used by [relational queries](https://orm.drizzle.team/docs/rqb)
   *
   * Defaults to {@link fromDriver} function
   * @example
   * For example, when querying bigint column via [RQB](https://orm.drizzle.team/docs/rqb) or JSON functions, the result field will be returned as it's string representation, as opposed to bigint from regular query
   * To handle that, we need a separate function to handle such field's mapping:
   * ```
   * fromJson(value: string): bigint {
   * 	return BigInt(value);
   * },
   * ```
   *
   * It'll cause the returned data to change from:
   * ```
   * {
   * 	customField: "5044565289845416380";
   * }
   * ```
   * to:
   * ```
   * {
   * 	customField: 5044565289845416380n;
   * }
   * ```
   */
  fromJson?: (value: T['jsonData']) => T['data'];
  /**
   * Optional selection modifier function, that is used for modifying selection of column inside JSON functions
   *
   * Additional mapping that could be required for such scenarios can be handled using {@link fromJson} function
   *
   * Used by [relational queries](https://orm.drizzle.team/docs/rqb)
   *
   * Following types are being casted to text by default: `binary`, `varbinary`, `time`, `datetime`, `decimal`, `float`, `bigint`
   * @example
   * For example, when using bigint we need to cast field to text to preserve data integrity
   * ```
   * forJsonSelect(identifier: SQL, sql: SQLGenerator): SQL {
   * 	return sql`cast(${identifier} as char)`
   * },
   * ```
   *
   * This will change query from:
   * ```
   * SELECT
   * 	json_build_object('bigint', `t`.`bigint`)
   * 	FROM
   * 	(
   * 		SELECT
   * 		`table`.`custom_bigint` AS `bigint`
   * 		FROM
   * 		`table`
   * 	) AS `t`
   * ```
   * to:
   * ```
   * SELECT
   * 	json_build_object('bigint', `t`.`bigint`)
   * 	FROM
   * 	(
   * 		SELECT
   * 		cast(`table`.`custom_bigint` as char) AS `bigint`
   * 		FROM
   * 		`table`
   * 	) AS `t`
   * ```
   *
   * Returned by query object will change from:
   * ```
   * {
   * 	bigint: 5044565289845416000; // Partial data loss due to direct conversion to JSON format
   * }
   * ```
   * to:
   * ```
   * {
   * 	bigint: "5044565289845416380"; // Data is preserved due to conversion of field to text before JSON-ification
   * }
   * ```
   */
  forJsonSelect?: (identifier: SQL, sql: SQLGenerator) => SQL;
}
```

Source: https://orm.drizzle.team/docs/mysql/data-querying

import Callout from '@mdx/Callout.astro';
import CodeTabs from "@mdx/CodeTabs.astro";
import Section from '@mdx/Section.astro';
import Flex from "@mdx/Flex.astro"
import LinksList from "@mdx/LinksList.astro"
import Prerequisites from "@mdx/Prerequisites.astro";

# Drizzle Queries + CRUD

<Prerequisites>
  - How to define your schema - [Schema Fundamentals](/docs/mysql/sql-schema-declaration)
  - How to connect to the database - [Connection Fundamentals](/docs/mysql/connect-overview)
</Prerequisites>

Drizzle gives you a few ways for querying your database and it's up to you to decide which one you'll need in your next project.
It can be either SQL-like syntax or Relational Syntax. Let's check them:

## Why SQL-like?
\
**If you know SQL, you know Drizzle.**

Other ORMs and data frameworks tend to deviate from or abstract away SQL, leading to a double learning curve: you need to learn both SQL and the framework's API.

Drizzle is the opposite.
We embrace SQL and built Drizzle to be SQL-like at its core, so you have little to no learning curve and full access to the power of SQL.

<Section>
```typescript copy
// Access your data
await db
  .select()
	.from(posts)
	.leftJoin(comments, eq(posts.id, comments.post_id))
	.where(eq(posts.id, 10))
```
```sql
SELECT *
FROM `posts`
LEFT JOIN `comments` ON `posts`.`id` = `comments`.`post_id`
WHERE `posts`.`id` = 10
```
</Section>

With SQL-like syntax, you can replicate much of what you can do with pure SQL and know 
exactly what Drizzle will do and what query will be generated. You can perform a wide range of queries, 
including select, insert, update, delete, as well as using aliases, WITH clauses, subqueries, prepared statements, 
and more. Let's look at more examples

<CodeTabs items={['insert', 'update', 'delete']}>
<Section>
```ts
await db.insert(users).values({ email: 'user@gmail.com' })
```
```sql
INSERT INTO `users` (`email`) VALUES ('user@gmail.com')
```
</Section>
<Section>
```ts
await db.update(users)
        .set({ email: 'user@gmail.com' })
        .where(eq(users.id, 1))
```
```sql
UPDATE `users`
SET `email` = 'user@gmail.com'
WHERE `users`.`id` = 1
```
</Section>
<Section>
```ts
await db.delete(users).where(eq(users.id, 1))
```
```sql
DELETE FROM `users` WHERE `users`.`id` = 1
```
</Section>
</CodeTabs>

## Why not SQL-like?

We're always striving for a perfectly balanced solution. While SQL-like queries cover 100% of your needs, 
there are certain common scenarios where data can be queried more efficiently.

We've built the Queries API so you can fetch relational, nested data from the database in the most convenient 
and performant way, without worrying about joins or data mapping.

**Drizzle always outputs exactly one SQL query**. Feel free to use it with serverless databases,
and never worry about performance or roundtrip costs!

<Section>
```ts
const result = await db.query.users.findMany({
	with: {
		posts: true
	},
});
```
{/* ```sql
SELECT * FROM users ...
``` */}
</Section>

## Advanced
With Drizzle, queries can be composed and partitioned in any way you want. You can compose filters 
independently from the main query, separate subqueries or conditional statements, and much more. 
Let's check a few advanced examples:

#### Compose a WHERE statement and then use it in a query
```ts
async function getProductsBy({
  name,
  category,
  maxPrice,
}: {
  name?: string;
  category?: string;
  maxPrice?: number;
}) {
  const filters: SQL[] = [];

  if (name) filters.push(like(products.name, name));
  if (category) filters.push(eq(products.category, category));
  if (maxPrice) filters.push(lte(products.price, maxPrice));

  return db
    .select()
    .from(products)
    .where(and(...filters));
}
```

#### Separate subqueries into different variables, and then use them in the main query
```ts
const subquery = db
	.select()
	.from(internalStaff)
	.leftJoin(customUser, eq(internalStaff.userId, customUser.id))
	.as('internal_staff');

const mainQuery = await db
	.select()
	.from(ticket)
	.leftJoin(subquery, eq(subquery.internal_staff.userId, ticket.staffId));
```

#### What's next?
<br/>
<Flex>
  <LinksList 
    title='Access your data'
    links={[
        ["Query", "/docs/mysql/rqb"], 
        ["Select", "/docs/mysql/select"],
        ["Insert", "/docs/mysql/insert"],
        ["Update", "/docs/mysql/update"],
        ["Delete", "/docs/mysql/delete"],
        ["Filters", "/docs/mysql/operators"],
        ["Joins", "/docs/mysql/joins"],
        ["sql`` operator", "/docs/mysql/sql"],
      ]}
  />
  <LinksList 
    title='Zero to Hero'
    links={[
        ["Migrations", "/docs/mysql/migrations"], 
      ]}
  />
</Flex>


Source: https://orm.drizzle.team/docs/mysql/delete

import Callout from '@mdx/Callout.astro';
import Section from '@mdx/Section.astro';

# SQL Delete
You can delete all rows in the table:
```typescript copy
await db.delete(users);
```
And you can delete with filters and conditions:
```typescript copy
await db.delete(users).where(eq(users.name, 'Dan'));
```

### Limit
Use `.limit()` to add `limit` clause to the query - for example:
<Section>
```typescript
await db.delete(users).where(eq(users.name, 'Dan')).limit(2);
```
```sql
delete from `users` where `users`.`name` = 'Dan' limit 2;
```
</Section>

### Order By
Use `.orderBy()` to add `order by` clause to the query, sorting the results by the specified fields:
<Section>
```typescript
import { asc, desc } from 'drizzle-orm';

await db.delete(users).where(eq(users.name, 'Dan')).orderBy(users.name);
await db.delete(users).where(eq(users.name, 'Dan')).orderBy(desc(users.name));

// order by multiple fields
await db.delete(users).where(eq(users.name, 'Dan')).orderBy(users.name, users.name2);
await db.delete(users).where(eq(users.name, 'Dan')).orderBy(asc(users.name), desc(users.name2));
```
```sql
delete from `users` where `users`.`name` = 'Dan' order by `users`.`name`;
delete from `users` where `users`.`name` = 'Dan' order by `users`.`name` desc;

delete from `users` where `users`.`name` = 'Dan' order by `users`.`name`, `users`.`name2`;
delete from `users` where `users`.`name` = 'Dan' order by `users`.`name` asc, `users`.`name2` desc;
```
</Section>



Source: https://orm.drizzle.team/docs/mysql/drizzle-config-file

import CodeTab from "@mdx/CodeTab.astro";
import CodeTabs from "@mdx/CodeTabs.astro";
import Section from "@mdx/Section.astro";
import Tab from "@mdx/Tab.astro";
import Tabs from "@mdx/Tabs.astro";
import Callout from "@mdx/Callout.astro";
import SchemaFilePaths from "@mdx/SchemaFilePaths.mdx"
import Prerequisites from "@mdx/Prerequisites.astro"
import Dialects from "@mdx/Dialects.mdx"
import Drivers from "@mdx/Drivers.mdx"
import DriversExamples from "@mdx/DriversExamples.mdx"
import Npx from "@mdx/Npx.astro"

# Drizzle Kit configuration file
<Prerequisites>
- Get started with Drizzle and `drizzle-kit` - [read here](/docs/mysql/get-started)
- Drizzle schema fundamentals - [read here](/docs/mysql/sql-schema-declaration)
- Database connection basics - [read here](/docs/mysql/connect-overview)
- Drizzle migrations fundamentals - [read here](/docs/mysql/migrations)
- Drizzle Kit [overview](/docs/mysql/kit-overview) and [config file](/docs/mysql/drizzle-config-file)
</Prerequisites>

Drizzle Kit lets you declare configuration options in `TypeScript` or `JavaScript` configuration files.

<Section>
```plaintext {5}
📦 <project root>
 ├ ...
 ├ 📂 drizzle
 ├ 📂 src
 ├ 📜 drizzle.config.ts
 └ 📜 package.json
```
<CodeTabs items={["drizzle.config.ts", "drizzle.config.js"]}>
<CodeTab>
```ts
import { defineConfig } from "drizzle-kit";

export default defineConfig({
  dialect: "mysql",
  schema: "./src/schema.ts",
  out: "./drizzle",
});
```
</CodeTab>
<CodeTab>
```js
import { defineConfig } from "drizzle-kit";

export default defineConfig({
  dialect: "mysql",
  schema: "./src/schema.ts",
  out: "./drizzle",
});
```
</CodeTab>
</CodeTabs>
</Section>

Example of an extended config file
```ts collapsable
import { defineConfig } from "drizzle-kit";

export default defineConfig({
  out: "./drizzle",
  dialect: "mysql",
  schema: "./src/schema.ts",

  dbCredentials: {
    url: "mysql://user:password@host:3306/dbname",
  },

  tablesFilter: "*",

  introspect: {
    casing: "camel",
  },

  migrations: {
    table: "__drizzle_migrations__",
  },

  breakpoints: true,
  verbose: true,
});

```

### Multiple configuration files
You can have multiple config files in the project, it's very useful when you have multiple database stages or multiple databases or different databases on the same project:
<Npx>
  drizzle-kit generate --config=drizzle-dev.config.ts
  drizzle-kit generate --config=drizzle-prod.config.ts
</Npx>
```plaintext {5-6}
📦 <project root>
 ├ 📂 drizzle
 ├ 📂 src
 ├ 📜 .env
 ├ 📜 drizzle-dev.config.ts
 ├ 📜 drizzle-prod.config.ts
 ├ 📜 package.json
 └ 📜 tsconfig.json
```

### Migrations folder
`out` param lets you define folder for your migrations, it's optional and `drizzle` by default.  
It's very useful since you can have many separate schemas for different databases in the same project 
and have different migration folders for them.  
  
Migration folder contains folders with `.sql` migration files which is used by `drizzle-kit`

<Section>
```plaintext {3}
📦 <project root>
 ├ ...
 ├ 📂 drizzle
 │ ├ 📂 20242409125510_premium_mister_fear
 │ ├ 📜 user.ts 
 │ ├ 📜 post.ts 
 │ └ 📜 comment.ts 
 ├ 📂 src
 ├ 📜 drizzle.config.ts
 └ 📜 package.json
```
```ts {6}
import { defineConfig } from "drizzle-kit";

export default defineConfig({
  dialect: "mysql",
  schema: "./src/schema/*",
  out: "./drizzle",
});
```
</Section>

## ---

### `dialect`
<rem025/>

Dialect of the database you're using 
|               |                                                 |
| :------------ | :-----------------------------------            |
| type        | <Dialects/>                                     |
| default        | --                                     |
| commands    | `generate`, `push`, `pull`, `studio`,  `migrate`, `up`, `export` |

<rem025/>
```ts {4}
import { defineConfig } from "drizzle-kit";

export default defineConfig({
  dialect: "mysql", 
});
```


### `schema`
<rem025/>

[`glob`](https://www.digitalocean.com/community/tools/glob?comments=true&glob=/**/*.js&matches=false&tests=//%20This%20will%20match%20as%20it%20ends%20with%20'.js'&tests=/hello/world.js&tests=//%20This%20won't%20match!&tests=/test/some/globs)
 based path to drizzle schema file(s) or folder(s) contaning schema files.
|               |                      |
| :------------ | :-----------------   |
| type          | `string` `string[]` |
| default        | --                    |
| commands      | `generate`, `push`, `export`, `studio`  |

<rem025/>
<SchemaFilePaths />


### `out`
<rem025/>

Defines output folder of your SQL migration files, json snapshots of your schema and `schema.ts` from `drizzle-kit pull` command.
|               |                      |
| :------------ | :-----------------   |
| type          | `string` `string[]` |
| default        | `drizzle`                    |
| commands      | `generate`, `pull`, `migrate`, `check`, `up` |

<rem025/>
```ts {4}
import { defineConfig } from "drizzle-kit";

export default defineConfig({
  out: "./drizzle", 
});
```

## ---

### `dbCredentials`
<rem025/>

Database connection credentials in a form of `url`, 
`user:password@host:port/db` params or exceptions drivers(<Drivers/>) specific connection options.

|               |                      |
| :------------ | :-----------------   |
| type          | <Dialects/> |
| default       | --                    |
| commands      | `push`, `pull`, `migrate`, `studio` |

<rem025/>

<CodeTabs items={["Connection string", "Connection params"]}>
```ts
import { defineConfig } from 'drizzle-kit'

export default defineConfig({
  dialect: "mysql",
  dbCredentials: {
    url: "mysql://user:password@host:port/db",
  }
});
```
```ts
import { defineConfig } from 'drizzle-kit'

export default defineConfig({
  dialect: "mysql",
  dbCredentials: {
    host: "host",
    port: 3306,
    user: "user",
    password: "password",
    database: "dbname",
    ssl: "...", // can be: string | SslOptions from mysql2
  }
});
```
</CodeTabs>

### `migrations`
<rem025/>

When running `drizzle-kit migrate` - drizzle will records about 
successfully applied migrations in your database in log table named `__drizzle_migrations`.

`migrations` config options lets you change both migrations log `table` name and `schema`.

|               |                      |
| :------------ | :-----------------   |
| type          | `{ table: string }` |
| default       | `{ table: "__drizzle_migrations" }`                    |
| commands      | `migrate`, `push`, `pull` |

<rem025/>

```ts
export default defineConfig({
  dialect: "mysql",
  schema: "./src/schema.ts",
  migrations: {
    table: 'my-migrations-table', // `__drizzle_migrations` by default
  },
});
```

### `introspect`
<rem025/>

Configuration for `drizzle-kit pull` command.

`casing` is responsible for in-code column keys casing

|               |                      |
| :------------ | :-----------------   |
| type          | `{ casing: "preserve" \| "camel" }` |
| default       | `{ casing: "camel" }`                    |
| commands      | `pull`   |

<rem025/>

<CodeTabs items={["camel", "preserve"]}>
<Section>
```ts
import * as p from "drizzle-orm/mysql-core"

export const users = p.mysqlTable("users", {
  id: p.int().primaryKey().autoincrement(),
  firstName: p.varchar("first-name", { length: 255 }),
  lastName: p.varchar("LastName", { length: 255 }),
  email: p.varchar("email", { length: 255 }),
  phoneNumber: p.varchar("phone_number", { length: 255 }),
});
```
```sql
SHOW COLUMNS FROM users;
```
```
  Field        | Type
--------------+--------------
 id           | int
 first-name   | varchar(255)
 LastName     | varchar(255)
 email        | varchar(255)
 phone_number | varchar(255)
```
</Section>
<Section>
```ts
import * as p from "drizzle-orm/mysql-core"

export const users = p.mysqlTable("users", {
  id: p.int().primaryKey().autoincrement(),
  "first-name": p.varchar("first-name", { length: 255 }),
  LastName: p.varchar("LastName", { length: 255 }),
  email: p.varchar("email", { length: 255 }),
  phone_number: p.varchar("phone_number", { length: 255 }),
});
```
```sql
SHOW COLUMNS FROM users;
```
```
  Field        | Type
--------------+--------------
 id           | int
 first-name   | varchar(255)
 LastName     | varchar(255)
 email        | varchar(255)
 phone_number | varchar(255)
```
</Section>
</CodeTabs>


## --- 

### `tablesFilter`
<Callout>
If you want to run multiple projects with one database - check out [our guide](/docs/mysql/goodies#multi-project-schema).
</Callout>
<rem025/>
`drizzle-kit push` and `drizzle-kit pull` will manage all tables by default.
You can configure the list of tables via `tablesFilter`.

`tablesFilter` option lets you specify [`glob`](https://www.digitalocean.com/community/tools/glob?comments=true&glob=/**/*.js&matches=false&tests=//%20This%20will%20match%20as%20it%20ends%20with%20'.js'&tests=/hello/world.js&tests=//%20This%20won't%20match!&tests=/test/some/globs) 
based table names filter, e.g. `["users", "user_info"]` or `"user*"`

|               |                      |
| :------------ | :-----------------   |
| type          | `string` `string[]` |
| default       | --                    |
| commands      | `push` `pull`  |

<rem025/>
```ts
import { defineConfig } from "drizzle-kit";

export default defineConfig({
  dialect: "mysql",
  tablesFilter: ["users", "posts", "project1_*"],
});
```

## ---

### `verbose`
<rem025/>

Print all SQL statements during `drizzle-kit push` command.

|               |                      |
| :------------ | :-----------------   |
| type          | `boolean` |
| default       | `false`                    |
| commands      | `pull`   |

<rem025/>

```ts
export default defineConfig({
  dialect: "mysql",
  verbose: false,
});
```

### `breakpoints`
<rem025/>

Drizzle Kit will automatically embed `--> statement-breakpoint` into generated SQL migration files, 
that's necessary for databases that do not support multiple DDL alternation statements in one transaction(MySQL and SQLite).

`breakpoints` option flag lets you switch it on and off

|               |                      |
| :------------ | :-----------------   |
| type          | `boolean` |
| default       | `true`                    |
| commands      | `generate` `pull`   |

<rem025/>

```ts
export default defineConfig({
  dialect: "mysql",
  breakpoints: false,
});
```

Source: https://orm.drizzle.team/docs/mysql/drizzle-kit-check

import CodeTab from "@mdx/CodeTab.astro";
import CodeTabs from "@mdx/CodeTabs.astro";
import Section from "@mdx/Section.astro";
import Tab from "@mdx/Tab.astro";
import Tabs from "@mdx/Tabs.astro";
import Callout from "@mdx/Callout.astro";
import Prerequisites from "@mdx/Prerequisites.astro";
import Npm from "@mdx/Npm.astro";
import Npx from "@mdx/Npx.astro";
import Dialects from "@mdx/Dialects.mdx"

# `drizzle-kit check`

<Prerequisites>
- Get started with Drizzle and `drizzle-kit` - [read here](/docs/mysql/get-started)
- Drizzle schema fundamentals - [read here](/docs/mysql/sql-schema-declaration)
- Database connection basics - [read here](/docs/mysql/connect-overview)
- Drizzle migrations fundamentals - [read here](/docs/mysql/migrations)
- Drizzle Kit [overview](/docs/mysql/kit-overview) and [config file](/docs/mysql/drizzle-config-file)
- `drizzle-kit generate` command - [read here](/docs/mysql/drizzle-kit-generate)
</Prerequisites>

`drizzle-kit check` command lets you check consistency of your generated SQL migrations history.

That's extremely useful when you have multiple developers working on the project and 
altering database schema on different branches - read more about [migrations for teams](/docs/mysql/kit-migrations-for-teams).

<br/>
<hr/>
<br/>

`drizzle-kit check` command requires you to specify `dialect` param, 
you can provide it either via [drizzle.config.ts](/docs/mysql/drizzle-config-file) config file or via CLI options

<CodeTabs items={["With config file", "As CLI options"]}>
<Section>
```ts {5}
// drizzle.config.ts
import { defineConfig } from "drizzle-kit";

export default defineConfig({
  dialect: "mysql",
});
```
```shell
npx drizzle-kit check
```
</Section>
```shell
npx drizzle-kit check --dialect=mysql
```
</CodeTabs>

### Multiple configuration files in one project
You can have multiple config files in the project, it's very useful when you have multiple database stages or multiple databases on the same project:
<Npx>
  drizzle-kit check --config=drizzle-dev.config.ts
  drizzle-kit check --config=drizzle-prod.config.ts
</Npx>
```plaintext {5-6}
📦 <project root>
 ├ 📂 drizzle
 ├ 📂 src
 ├ 📜 .env
 ├ 📜 drizzle-dev.config.ts
 ├ 📜 drizzle-prod.config.ts
 ├ 📜 package.json
 └ 📜 tsconfig.json
```

### Extended list of configurations
We recommend configuring `drizzle-kit` through [drizzle.config.ts](/docs/mysql/drizzle-config-file) file, 
yet you can provide all configuration options through CLI if necessary, e.g. in CI/CD pipelines, etc.
<rem025/>
|           |            |                                                                         |
| :-------- | :--------- | :---------------------------------------------------------------------- |
| `dialect` | `required` | Database dialect you are using. Can be <Dialects/> |
| `out`     |            | Migrations folder, default=`./drizzle`                                  |
| `config`  |            | Configuration file path, default=`drizzle.config.ts`                           |
<br/>
<Npx>
drizzle-kit check --dialect=mysql
drizzle-kit check --dialect=mysql --out=./migrations-folder
</Npx>


Source: https://orm.drizzle.team/docs/mysql/drizzle-kit-export

import CodeTab from "@mdx/CodeTab.astro";
import CodeTabs from "@mdx/CodeTabs.astro";
import Section from "@mdx/Section.astro";
import Tab from "@mdx/Tab.astro";
import Tabs from "@mdx/Tabs.astro";
import Callout from "@mdx/Callout.astro";
import Prerequisites from "@mdx/Prerequisites.astro"
import Npx from "@mdx/Npx.astro";
import SchemaFilePaths from "@mdx/SchemaFilePaths.mdx"
import Dialects from "@mdx/Dialects.mdx"

# `drizzle-kit export` 

<Prerequisites>
- Get started with Drizzle and `drizzle-kit` - [read here](/docs/mysql/get-started)
- Drizzle schema fundamentals - [read here](/docs/mysql/sql-schema-declaration)
- Database connection basics - [read here](/docs/mysql/connect-overview)
- Drizzle migrations fundamentals - [read here](/docs/mysql/migrations)
- Drizzle Kit [overview](/docs/mysql/kit-overview) and [config file](/docs/mysql/drizzle-config-file)
</Prerequisites>


<br/>

`drizzle-kit export` lets you export SQL representation of Drizzle schema and print in console SQL DDL representation on it.
<Callout collapsed="How it works under the hood?">
Drizzle Kit `export` command triggers a sequence of events:
1. It will read through your Drizzle schema file(s) and compose a json snapshot of your schema
2. Based on the current json snapshot it will generate SQL DDL statements
3. Output SQL DDL statements to console
</Callout>

It's designed to cover [codebase first](/docs/mysql/migrations) approach of managing Drizzle migrations. 
You can export the SQL representation of the Drizzle schema, allowing external tools like Atlas to handle all the migrations for you

`drizzle-kit export` command requires you to provide both `dialect` and `schema` path options, 
you can set them either via [drizzle.config.ts](/docs/mysql/drizzle-config-file) config file or via CLI options
<CodeTabs items={["With config file", "As CLI options"]}>
<Section>
```ts
// drizzle.config.ts
import { defineConfig } from "drizzle-kit";

export default defineConfig({
  dialect: "mysql",
  schema: "./src/schema.ts",
});
```
```shell
npx drizzle-kit export
```
</Section>

```shell
npx drizzle-kit export --dialect=mysql --schema=./src/schema.ts
```
</CodeTabs>

### Schema files path
You can have a single `schema.ts` file or as many schema files as you want spread out across the project. 
Drizzle Kit requires you to specify path(s) to them as a [glob](https://www.digitalocean.com/community/tools/glob?comments=true&glob=/**/*.js&matches=false&tests=//%20This%20will%20match%20as%20it%20ends%20with%20'.js'&tests=/hello/world.js&tests=//%20This%20won't%20match!&tests=/test/some/globs) via `schema` configuration option.

<SchemaFilePaths/>

### Multiple configuration files in one project
You can have multiple config files in the project, it's very useful when you have multiple database stages or multiple databases or different databases on the same project:
<Npx>
  drizzle-kit export --config=drizzle-dev.config.ts
  drizzle-kit export --config=drizzle-prod.config.ts
</Npx>
```plaintext {5-6}
📦 <project root>
 ├ 📂 drizzle
 ├ 📂 src
 ├ 📜 .env
 ├ 📜 drizzle-dev.config.ts
 ├ 📜 drizzle-prod.config.ts
 ├ 📜 package.json
 └ 📜 tsconfig.json
```

### Extended list of available configurations
`drizzle-kit export` has a list of cli-only options

<rem025/>

|               |                                                      |
| :--------     | :--------------------------------------------------- |
| `--sql`       | generating SQL representation of Drizzle Schema               |

By default, Drizzle Kit outputs SQL files, but in the future, we want to support different formats

<rem025/>

<Npx>
drizzle-kit export --sql=true
</Npx>

<br/>
<hr/>
<br/>
We recommend configuring `drizzle-kit` through [drizzle.config.ts](/docs/mysql/drizzle-config-file) file, 
yet you can provide all configuration options through CLI if necessary, e.g. in CI/CD pipelines, etc.

|               |            |                                                                            |
| :------------ | :-------   | :----------------------------------------------------------------------    |
| `dialect`     | `required` | Database dialect, one of <Dialects/>                                       |
| `schema`      | `required` | Path to typescript schema file(s) or folder(s) with multiple schema files  |
| `config`      |            | Configuration file path, default is `drizzle.config.ts`                    |

### Example
Example of how to export drizzle schema to console with Drizzle schema located in `./src/schema.ts`

We will also place drizzle config file in the `configs` folder.

Let's create config file:

```plaintext {4}
📦 <project root>
 ├ 📂 configs
 │ └ 📜 drizzle.config.ts
 ├ 📂 src
 │ └ 📜 schema.ts
 └ …
```
```ts filename='drizzle.config.ts'
import { defineConfig } from "drizzle-kit";

export default defineConfig({
  dialect: "mysql",
  schema: "./src/schema.ts",
});
```

```ts filename='schema.ts'
import { mysqlTable, int, text } from 'drizzle-orm/mysql-core'

export const users = mysqlTable('users', {
	id: int('id').primaryKey().autoincrement(),
	email: text('email').notNull(),
	name: text('name')
});
```

Now let's run
```shell
npx drizzle-kit export --config=./configs/drizzle.config.ts
```
And it will successfully output SQL representation of drizzle schema
```bash
CREATE TABLE "users" (
        `id` int AUTO_INCREMENT PRIMARY KEY,
        `email` varchar(255) NOT NULL,
        "name" text
);
```

Source: https://orm.drizzle.team/docs/mysql/drizzle-kit-generate

import CodeTab from "@mdx/CodeTab.astro";
import CodeTabs from "@mdx/CodeTabs.astro";
import Section from "@mdx/Section.astro";
import Tab from "@mdx/Tab.astro";
import Tabs from "@mdx/Tabs.astro";
import Callout from "@mdx/Callout.astro";
import Prerequisites from "@mdx/Prerequisites.astro"
import Npx from "@mdx/Npx.astro";
import SchemaFilePaths from "@mdx/SchemaFilePaths.mdx"
import Dialects from "@mdx/Dialects.mdx"

# `drizzle-kit generate` 

<Prerequisites>
- Get started with Drizzle and `drizzle-kit` - [read here](/docs/mysql/get-started)
- Drizzle schema fundamentals - [read here](/docs/mysql/sql-schema-declaration)
- Database connection basics - [read here](/docs/mysql/connect-overview)
- Drizzle migrations fundamentals - [read here](/docs/mysql/migrations)
- Drizzle Kit [overview](/docs/mysql/kit-overview) and [config file](/docs/mysql/drizzle-config-file)
</Prerequisites>


<br/>

`drizzle-kit generate` lets you generate SQL migrations based on your Drizzle schema upon declaration or on subsequent schema changes.
<Callout collapsed="How it works under the hood?">
Drizzle Kit `generate` command triggers a sequence of events:
1. It will read through your Drizzle schema file(s) and compose a json snapshot of your schema
2. It will read through your previous migrations folders and compare current json snapshot to the most recent one
3. Based on json differences it will generate SQL migrations
4. Save `migration.sql` and `snapshot.json` in migration folder under current timestamp

<Section>
```typescript filename="src/schema.ts"
import * as p from "drizzle-orm/mysql-core";

export const users = p.mysqlTable("users", {
  id: p.int().primaryKey().autoincrement(),
  name: p.varchar({ length: 255 }),
  email: p.varchar({ length: 255 }).unique(), 
});
```
```                                  
┌────────────────────────┐                  
│ $ drizzle-kit generate │                  
└─┬──────────────────────┘                  
  │                                           
  └ 1. read previous migration folders
    2. find diff between current and previous schema
    3. prompt developer for renames if necessary
  ┌ 4. generate SQL migration and persist to file
  │    ┌─┴───────────────────────────────────────┐  
  │      📂 drizzle       
  │      └ 📂 20242409125510_premium_mister_fear
  │        ├ 📜 migration.sql
  │        └ 📜 snapshot.json
  v
```
```sql
-- drizzle/20242409125510_premium_mister_fear/migration.sql

CREATE TABLE `users` (
 `id` int AUTO_INCREMENT PRIMARY KEY,
 `name` varchar(255),
 `email` varchar(255),
 CONSTRAINT `email_unique` UNIQUE INDEX(`email`)
);
```
</Section>
</Callout>

It's designed to cover [code first](/docs/mysql/migrations) approach of managing Drizzle migrations. 
You can apply generated migrations using [`drizzle-kit migrate`](/docs/mysql/drizzle-kit-migrate), using drizzle-orm's `migrate()`, 
using external migration tools like [bytebase](https://www.bytebase.com/) or running migrations yourself directly on the database. 

`drizzle-kit generate` command requires you to provide both `dialect` and `schema` path options, 
you can set them either via [drizzle.config.ts](/docs/mysql/drizzle-config-file) config file or via CLI options
<CodeTabs items={["With config file", "As CLI options"]}>
<Section>
```ts
// drizzle.config.ts
import { defineConfig } from "drizzle-kit";

export default defineConfig({
  dialect: "mysql",
  schema: "./src/schema.ts",
});
```
```shell
npx drizzle-kit generate
```
</Section>

```shell
npx drizzle-kit generate --dialect=mysql --schema=./src/schema.ts
```
</CodeTabs>

### Schema files path
You can have a single `schema.ts` file or as many schema files as you want spread out across the project. 
Drizzle Kit requires you to specify path(s) to them as a [glob](https://www.digitalocean.com/community/tools/glob?comments=true&glob=/**/*.js&matches=false&tests=//%20This%20will%20match%20as%20it%20ends%20with%20'.js'&tests=/hello/world.js&tests=//%20This%20won't%20match!&tests=/test/some/globs) via `schema` configuration option.

<SchemaFilePaths/>


### Custom migration file name
You can set custom migration file names by providing `--name` CLI option
```shell
npx drizzle-kit generate --name=init
```
```plaintext {3}
📦 <project root>
 ├ 📂 drizzle
 │ └ 📂 20242409125510_init
 │   ├ 📜 snapshot.json
 │   └ 📜 migration.sql
 ├ 📂 src
 └ …
```

### Multiple configuration files in one project
You can have multiple config files in the project, it's very useful when you have multiple database stages or multiple databases or different databases on the same project:
<Npx>
  drizzle-kit generate --config=drizzle-dev.config.ts
  drizzle-kit generate --config=drizzle-prod.config.ts
</Npx>
```plaintext {5-6}
📦 <project root>
 ├ 📂 drizzle
 ├ 📂 src
 ├ 📜 .env
 ├ 📜 drizzle-dev.config.ts
 ├ 📜 drizzle-prod.config.ts
 ├ 📜 package.json
 └ 📜 tsconfig.json
```

### Custom migrations
You can generate empty migration files to write your own custom SQL migrations 
for DDL alternations currently not supported by Drizzle Kit or data seeding. Extended docs on custom migrations - [see here](/docs/mysql/kit-custom-migrations)

```shell
drizzle-kit generate --custom --name=seed-users
```
<Section>
```plaintext {4}
📦 <project root>
 ├ 📂 drizzle
 │ ├ 📂 20242409125510_init
 │ └ 📂 20242409125510_seed-users
 ├ 📂 src
 └ …
```
```sql
-- ./drizzle/20242409125510_seed-users/migration.sql

INSERT INTO `users` (`name`) VALUES('Dan');
INSERT INTO `users` (`name`) VALUES('Andrew');
INSERT INTO `users` (`name`) VALUES('Dandrew');
```
</Section>

### Ignore conflicts

In case you need `generate` command to skip commutativity checks and bypass it, you can use `--ignore-conflicts`. If there is a situation you want to use it, then
there is a big chance that `drizzle-kit` didn't check migrations right and it's a bug. Please report us your case, so we can fix it

```shell
drizzle-kit generate --ignore-conflicts
```

### Extended list of available configurations
`drizzle-kit generate` has a list of cli-only options

<rem025/>

|               |                                                      |
| :--------     | :--------------------------------------------------- |
| `custom`      | generate empty SQL for custom migration              |
| `name`        | generate migration with custom name                  |
| `ignore-conflicts` | skip commutativity conflict checks, default is `false` |

<rem025/>

<Npx>
drizzle-kit generate --name=init
drizzle-kit generate --name=seed_users --custom
drizzle-kit generate --ignore-conflicts
</Npx>

<br/>
<hr/>
<br/>
We recommend configuring `drizzle-kit` through [drizzle.config.ts](/docs/mysql/drizzle-config-file) file, 
yet you can provide all configuration options through CLI if necessary, e.g. in CI/CD pipelines, etc.

|               |            |                                                                            |
| :------------ | :-------   | :----------------------------------------------------------------------    |
| `dialect`     | `required` | Database dialect, one of <Dialects/>                                       |
| `schema`      | `required` | Path to typescript schema file(s) or folder(s) with multiple schema files  |
| `out`         |            | Migrations output folder, default is `./drizzle`                           |
| `config`      |            | Configuration file path, default is `drizzle.config.ts`                    |
| `breakpoints` |            | SQL statements breakpoints, default is `true`                              |


### Extended example
Example of how to create a custom MySQL migration file named `0001_seed-users.sql` 
with Drizzle schema located in `./src/schema.ts` and migrations folder named `./migrations` instead of default `./drizzle`.

We will also place drizzle config file in the `configs` folder.

Let's create config file:

```plaintext {4}
📦 <project root>
 ├ 📂 migrations
 ├ 📂 configs
 │ └ 📜 drizzle.config.ts
 ├ 📂 src
 └ …
```
```ts filename='drizzle.config.ts'
import { defineConfig } from "drizzle-kit";

export default defineConfig({
  dialect: "mysql",
  schema: "./src/schema.ts",
  out: "./migrations",
});
```

Now let's run
```shell
npx drizzle-kit generate --config=./configs/drizzle.config.ts --name=seed-users --custom
```
And it will successfully generate
<Section>
```plaintext {5}
📦 <project root>
 ├ …
 ├ 📂 migrations
 │ ├ 📂 20242409125510_init
 │ └ 📂 20242409125510_seed-users
 └ …
```
```sql
-- ./drizzle/20242409125510_seed-users/migration.sql

INSERT INTO `users` (`name`) VALUES('Dan');
INSERT INTO `users` (`name`) VALUES('Andrew');
INSERT INTO `users` (`name`) VALUES('Dandrew');
```
</Section>


Source: https://orm.drizzle.team/docs/mysql/drizzle-kit-migrate

import CodeTab from "@mdx/CodeTab.astro";
import CodeTabs from "@mdx/CodeTabs.astro";
import Section from "@mdx/Section.astro";
import Tab from "@mdx/Tab.astro";
import Tabs from "@mdx/Tabs.astro";
import Callout from "@mdx/Callout.astro";
import Prerequisites from "@mdx/Prerequisites.astro";
import Npx from "@mdx/Npx.astro";

# `drizzle-kit migrate`
<Prerequisites>
- Get started with Drizzle and `drizzle-kit` - [read here](/docs/mysql/get-started)
- Drizzle schema fundamentals - [read here](/docs/mysql/sql-schema-declaration)
- Database connection basics - [read here](/docs/mysql/connect-overview)
- Drizzle migrations fundamentals - [read here](/docs/mysql/migrations)
- Drizzle Kit [overview](/docs/mysql/kit-overview) and [config file](/docs/mysql/drizzle-config-file)
- `drizzle-kit generate` command - [read here](/docs/mysql/drizzle-kit-generate)
</Prerequisites>
<br/>


`drizzle-kit migrate` lets you apply SQL migrations generated by [`drizzle-kit generate`](/docs/mysql/drizzle-kit-generate). 
It's designed to cover [code first(option 3)](/docs/mysql/migrations) approach of managing Drizzle migrations. 

<Callout collapsed="How it works under the hood?">
Drizzle Kit `migrate` command triggers a sequence of events:
1. Reads through migration folder and read all `.sql` migration files
2. Connects to the database and fetches entries from drizzle migrations log table
3. Based on previously applied migrations it will decide which new migrations to run
4. Runs SQL migrations and logs applied migrations to drizzle migrations table

<Section>
```plaintext
  ├ 📂 drizzle       
  │ ├ 📂 20242409125510_premium_mister_fear
  │ └ 📂 20242409135510_delicate_professor_xavie
  └ …
```
```plaintext
┌───────────────────────┐                  
│ $ drizzle-kit migrate │                  
└─┬─────────────────────┘                  
  │                                                         ┌──────────────────────────┐                                         
  └ 1. reads migration.sql files in migrations folder       │                          │
    2. fetch migration history from database -------------> │                          │
  ┌ 3. pick previously unapplied migrations <-------------- │         DATABASE         │
  └ 4. apply new migration to the database ---------------> │                          │
                                                            │                          │
                                                            └──────────────────────────┘
[✓] done!        
```
</Section>
</Callout>

`drizzle-kit migrate` command requires you to specify both `dialect` and database connection credentials, 
you can provide them either via [drizzle.config.ts](/docs/mysql/drizzle-config-file) config file or via CLI options

<CodeTabs items={["With config file", "As CLI options"]}>
<Section>
```ts {5,8}
// drizzle.config.ts
import { defineConfig } from "drizzle-kit";

export default defineConfig({
  dialect: "mysql",
  schema: "./src/schema.ts",
  dbCredentials: {
    url: "mysql://user:password@host:port/dbname"
  },
});
```
```shell
npx drizzle-kit migrate
```
</Section>
```shell
npx drizzle-kit migrate --dialect=mysql --url=mysql://user:password@host:port/dbname
```
</CodeTabs>

### Applied migrations log in the database
Upon running migrations Drizzle Kit will persist records about successfully applied migrations in your database. 
It will store them in migrations log table named `__drizzle_migrations`.

You can customise the **table** name of that log table via drizzle config file:
```ts filename="drizzle.config.ts" {8}
export default defineConfig({
  dialect: "mysql",
  schema: "./src/schema.ts",
  dbCredentials: {
    url: "mysql://user:password@host:3306/dbname"
  },
  migrations: {
    table: 'my-migrations-table', // `__drizzle_migrations` by default
  },
});
```

### Multiple configuration files in one project
You can have multiple config files in the project, it's very useful when you have multiple database stages or multiple databases on the same project:
<Npx>
  drizzle-kit migrate --config=drizzle-dev.config.ts
  drizzle-kit migrate --config=drizzle-prod.config.ts
</Npx>
```plaintext {5-6}
📦 <project root>
 ├ 📂 drizzle
 ├ 📂 src
 ├ 📜 .env
 ├ 📜 drizzle-dev.config.ts
 ├ 📜 drizzle-prod.config.ts
 ├ 📜 package.json
 └ 📜 tsconfig.json
```

### Extended example
Let's generate SQL migration and apply it to our database using `drizzle-kit generate` and `drizzle-kit migrate` commands

```plaintext
📦 <project root>
 ├ 📂 drizzle
 ├ 📂 src
 │ ├ 📜 schema.ts
 │ └ 📜 index.ts
 ├ 📜 drizzle.config.ts
 └ …
```
<CodeTabs items={["drizzle.config.ts", "src/schema.ts"]}>
```ts
import { defineConfig } from "drizzle-kit";

export default defineConfig({
  dialect: "mysql",
  schema: "./src/schema.ts",
  dbCredentials: {
    url: "mysql://user:password@host:3306/dbname"
  },
  migrations: {
    table: 'journal', 
  },
});
```
```ts 
import * as p from "drizzle-orm/mysql-core";

export const users = p.mysqlTable("users", {
  id: p.int().primaryKey().autoincrement(),
  name: p.varchar({ length: 255 }),
})
```
</CodeTabs>

Now let's run
```shell
npx drizzle-kit generate --name=init
```
it will generate
<Section>
```plaintext {4}
📦 <project root>
 ├ …
 ├ 📂 migrations
 │ ├ 📂 20242409125510_init
 └ …
```
```sql
-- ./20242409125510_init/0000_init.sql

CREATE TABLE `users`(
  `id` int AUTO_INCREMENT PRIMARY KEY,
  `name` varchar(255)
)
```
</Section>

Now let's run
```shell
npx drizzle-kit migrate
```

and our SQL migration is now successfully applied to the database ✅


Source: https://orm.drizzle.team/docs/mysql/drizzle-kit-pull

import CodeTab from "@mdx/CodeTab.astro";
import CodeTabs from "@mdx/CodeTabs.astro";
import Section from "@mdx/Section.astro";
import Tab from "@mdx/Tab.astro";
import Tabs from "@mdx/Tabs.astro";
import Callout from "@mdx/Callout.astro";
import Prerequisites from "@mdx/Prerequisites.astro";
import Drivers from "@mdx/Drivers.mdx"
import Dialects from "@mdx/Dialects.mdx"
import Npm from "@mdx/Npm.astro"
import Npx from "@mdx/Npx.astro"

# `drizzle-kit pull`

<Prerequisites>
- Get started with Drizzle and `drizzle-kit` - [read here](/docs/mysql/get-started)
- Drizzle schema fundamentals - [read here](/docs/mysql/sql-schema-declaration) 
- Database connection basics - [read here](/docs/mysql/connect-overview) 
- Drizzle migrations fundamentals - [read here](/docs/mysql/migrations) 
- Drizzle Kit [overview](/docs/mysql/kit-overview) and [config file](/docs/mysql/drizzle-config-file) docs
</Prerequisites>

`drizzle-kit pull` lets you literally pull(introspect) your existing database schema and generate `schema.ts` drizzle schema file, 
it is designed to cover [database first](/docs/mysql/migrations) approach of Drizzle migrations.

<Callout collapsed="How it works under the hood?">
When you run Drizzle Kit `pull` command it will:
1. Pull database schema(DDL) from your existing database
2. Generate `schema.ts` drizzle schema file and save it to `out` folder

<Section>
```
                                  ┌────────────────────────┐      ┌─────────────────────────┐ 
                                  │                        │ <---  CREATE TABLE `users` (
┌──────────────────────────┐      │                        │        `id` int auto_increment primary key,
│ ~ drizzle-kit pull       │      │                        │        `name` varchar(255),
└─┬────────────────────────┘      │        DATABASE        │        `email` varchar(255) unique
  │                               │                        │       );
  └ Pull datatabase schema -----> │                        │
  ┌ Generate Drizzle       <----- │                        │
  │ schema TypeScript file        └────────────────────────┘
  │
  v
```
```typescript
import * as p from "drizzle-orm/mysql-core";

export const users = p.mysqlTable(
  "users",
  {
    id: p.int().autoincrement().primaryKey(),
    name: p.varchar({ length: 255 }),
    email: p.varchar({ length: 255 }),
  },
  (table) => [p.uniqueIndex("email").on(table.email)]
);
```
</Section>
</Callout>

It is a great approach if you need to manage database schema outside of your TypeScript project or 
you're using database, which is managed by somebody else.

<br/>
<hr/>
<br/>

`drizzle-kit pull` requires you to specify `dialect` and either
database connection `url` or `user:password@host:port/db` params, you can provide them
either via [drizzle.config.ts](/docs/mysql/drizzle-config-file) config file or via CLI options:

<CodeTabs items={["With config file", "With CLI options"]}>
<Section>
```ts
// drizzle.config.ts
import { defineConfig } from "drizzle-kit";

export default defineConfig({
  dialect: "mysql",
  dbCredentials: {
    url: "mysql://user:password@host:3306/dbname",
  },
});
```
```shell
npx drizzle-kit pull
```
</Section>

```shell
npx drizzle-kit pull --dialect=mysql --url=mysql://user:password@host:3306/dbname
```
</CodeTabs>

### Multiple configuration files in one project

You can have multiple config files in the project, it's very useful when you have multiple database stages or multiple databases or different databases on the same project:

<Npx>
  drizzle-kit pull --config=drizzle-dev.config.ts
  drizzle-kit pull --config=drizzle-prod.config.ts
</Npx>
```plaintext {5-6}
📦 <project root>
 ├ 📂 drizzle
 ├ 📂 src
 ├ 📜 .env
 ├ 📜 drizzle-dev.config.ts
 ├ 📜 drizzle-prod.config.ts
 ├ 📜 package.json
 └ 📜 tsconfig.json
```

### Initial pull

You can use the `--init` flag to mark the pulled schema as an applied migration in your database, 
so that all subsequent migrations are diffed against the initial one

```shell
npx drizzle-kit pull --init
```

### Including tables
`drizzle-kit pull` will introspect all MySQL tables by default.
You can configure the list of tables via `tablesFilter`.

|                |                                                                                               |
| :------------- | :-------------------------------------------------------------------------------------------- |
| `tablesFilter` | `glob` based table names filter, e.g. `["users", "user_info"]` or `"user*"`. Default is `"*"` |
<br/>

Let's configure drizzle-kit to introspect **all tables** in the connected MySQL database.

<Section>
```ts filename="drizzle.config.ts" {8}
import { defineConfig } from "drizzle-kit";

export default defineConfig({
  dialect: "mysql",
  dbCredentials: {
    url: "mysql://user:password@host:3306/dbname",
  },
  tablesFilter: ["*"],
});
```
```shell
npx drizzle-kit pull
```
</Section>

### Extended list of configurations
We recommend configuring `drizzle-kit` through [drizzle.config.ts](/docs/mysql/drizzle-config-file) file, 
yet you can provide all configuration options through CLI if necessary, e.g. in CI/CD pipelines, etc.

|                     |            |                                                                           |
| :------------------ | :--------- | :------------------------------------------------------------------------ |
| `dialect`           | `required` | Database dialect, one of <Dialects/>                                      |
| `out`               |            | Migrations output folder path, default is `./drizzle`                     |
| `url`               |            | Database connection string                                                |
| `user`              |            | Database user                                                             |
| `password`          |            | Database password                                                         |
| `host`              |            | Host                                                                      |
| `port`              |            | Port                                                                      |
| `database`          |            | Database name                                                             |
| `config`            |            | Configuration file path, default is `drizzle.config.ts`                          |
| `introspect-casing` |            | Strategy for JS keys creation in columns, tables, etc. `preserve` `camel` |
| `tablesFilter`      |            | Table name filter                                                         |

<Npx>
drizzle-kit pull --dialect=mysql --url=mysql://user:password@host:3306/dbname
drizzle-kit pull --dialect=mysql --tablesFilter='user*' url=mysql://user:password@host:3306/dbname
</Npx>

{/* TODO update gifs */}
![](@/assets/gifs/introspect_mysql.gif)


Source: https://orm.drizzle.team/docs/mysql/drizzle-kit-push

import CodeTab from "@mdx/CodeTab.astro";
import CodeTabs from "@mdx/CodeTabs.astro";
import Section from "@mdx/Section.astro";
import Tab from "@mdx/Tab.astro";
import Tabs from "@mdx/Tabs.astro";
import Callout from "@mdx/Callout.astro";
import Prerequisites from "@mdx/Prerequisites.astro";
import Npx from "@mdx/Npx.astro";
import SchemaFilePaths from "@mdx/SchemaFilePaths.mdx";
import Drivers from "@mdx/Drivers.mdx"
import Dialects from "@mdx/Dialects.mdx"
import DriversExamples from "@mdx/DriversExamples.mdx"

# `drizzle-kit push`

<Prerequisites>
- Get started with Drizzle and `drizzle-kit` - [read here](/docs/mysql/get-started)
- Drizzle schema fundamentals - [read here](/docs/mysql/sql-schema-declaration) 
- Database connection basics - [read here](/docs/mysql/connect-overview) 
- Drizzle migrations fundamentals - [read here](/docs/mysql/migrations) 
- Drizzle Kit [overview](/docs/mysql/kit-overview) and [config file](/docs/mysql/drizzle-config-file) docs
</Prerequisites>


`drizzle-kit push` lets you literally push your schema and subsequent schema changes directly to the
database while omitting SQL files generation, it's designed to cover [code first](/docs/mysql/migrations)
approach of Drizzle migrations.

<Callout collapsed="How it works under the hood?">
When you run Drizzle Kit `push` command it will:
1. Read through your Drizzle schema file(s) and compose a json snapshot of your schema
2. Pull(introspect) database schema 
3. Based on differences between those two it will generate SQL migrations
4. Apply SQL migrations to the database

<Section>
```typescript filename="src/schema.ts"
import * as p from "drizzle-orm/mysql-core";

export const users = p.mysqlTable("users", {
  id: p.int().primaryKey().autoincrement(),
  name: p.varchar({ length: 255 }),
});
```
```
┌─────────────────────┐                  
│ ~ drizzle-kit push  │                  
└─┬───────────────────┘                  
  │                                           ┌──────────────────────────┐
  └ Pull current datatabase schema ---------> │                          │
                                              │                          │
  ┌ Generate alternations based on diff <---- │         DATABASE         │
  │                                           │                          │
  └ Apply migrations to the database -------> │                          │
                                       │      └──────────────────────────┘
                                       │
  ┌────────────────────────────────────┴────────────────┐
   create table `users` (`id` int AUTO_INCREMENT PRIMARY KEY, `name` varchar(255));
```
</Section>
</Callout>

It's the best approach for rapid prototyping and we've seen dozens of teams
and solo developers successfully using it as a primary migrations flow in their production applications.
It pairs exceptionally well with blue/green deployment strategy and serverless databases like
[Planetscale](https://planetscale.com), [Neon](https://neon.tech), [Turso](https://turso.tech/drizzle) and others.

<br/>
<hr/>
<br/>


`drizzle-kit push` requires you to specify `dialect`, path to the `schema` file(s) and either
database connection `url` or `user:password@host:port/db` params, you can provide them
either via [drizzle.config.ts](/docs/mysql/drizzle-config-file) config file or via CLI options:

<CodeTabs items={["With config file", "With CLI options"]}>
<Section>
```ts
// drizzle.config.ts
import { defineConfig } from "drizzle-kit";

export default defineConfig({
  dialect: "mysql",
  schema: "./src/schema.ts",
  dbCredentials: {
    url: "mysql://user:password@host:3306/dbname",
  },
});
```
```shell
npx drizzle-kit push
```
</Section>

```shell
npx drizzle-kit push --dialect=mysql --schema=./src/schema.ts --url=mysql://user:password@host:3306/dbname
```

</CodeTabs>

### Schema files path

You can have a single `schema.ts` file or as many schema files as you want spread out across the project.
Drizzle Kit requires you to specify path(s) to them as a [glob](https://www.digitalocean.com/community/tools/glob?comments=true&glob=/**/*.js&matches=false&tests=//%20This%20will%20match%20as%20it%20ends%20with%20'.js'&tests=/hello/world.js&tests=//%20This%20won't%20match!&tests=/test/some/globs) via `schema` configuration option.

<SchemaFilePaths />

### Multiple configuration files in one project

You can have multiple config files in the project, it's very useful when you have multiple database stages or multiple databases or different databases on the same project:

<Npx>
  drizzle-kit push --config=drizzle-dev.config.ts
  drizzle-kit push --config=drizzle-prod.config.ts
</Npx>
```plaintext {5-6}
📦 <project root>
 ├ 📂 drizzle
 ├ 📂 src
 ├ 📜 .env
 ├ 📜 drizzle-dev.config.ts
 ├ 📜 drizzle-prod.config.ts
 ├ 📜 package.json
 └ 📜 tsconfig.json
```

### Including tables
`drizzle-kit push` will manage all MySQL tables by default.
You can configure the list of tables via `tablesFilter`.

|                |                                                                                               |
| :------------- | :-------------------------------------------------------------------------------------------- |
| `tablesFilter` | `glob` based table names filter, e.g. `["users", "user_info"]` or `"user*"`. Default is `"*"` |
<br/>

Let's configure drizzle-kit to operate with **all tables** in the connected MySQL database.

<Section>
```ts filename="drizzle.config.ts" {9}
import { defineConfig } from "drizzle-kit";

export default defineConfig({
  dialect: "mysql",
  schema: "./src/schema.ts",
  dbCredentials: {
    url: "mysql://user:password@host:3306/dbname",
  },
  tablesFilter: ["*"],
});
```
```shell
npx drizzle-kit push
```
</Section>

### Extended list of configurations

`drizzle-kit push` has a list of cli-only options

<rem025/>

|           |                                                          |
| :-------- | :---------------------------------------------------     |
| `verbose` | print all SQL statements prior to execution              |
| `explain` | print the planned SQL changes, without applying them (dry run)  |
| `force`   | auto-accept all data-loss statements                     |
<br/>
<Npx>
drizzle-kit push --explain --verbose --force
</Npx>

<br/>
<hr/>
<br/>
We recommend configuring `drizzle-kit` through [drizzle.config.ts](/docs/mysql/drizzle-config-file) file, 
yet you can provide all configuration options through CLI if necessary, e.g. in CI/CD pipelines, etc.

|                     |            |                                                                           |
| :------------------ | :--------- | :------------------------------------------------------------------------ |
| `dialect`           | `required` | Database dialect, one of <Dialects/>                                      |
| `schema`            | `required` | Path to typescript schema file(s) or folder(s) with multiple schema files |
| `tablesFilter`      |            | Table name filter                                                         |
| `url`               |            | Database connection string                                                |
| `user`              |            | Database user                                                             |
| `password`          |            | Database password                                                         |
| `host`              |            | Host                                                                      |
| `port`              |            | Port                                                                      |
| `database`          |            | Database name                                                             |
| `config`            |            | Configuration file path, default=`drizzle.config.ts`                             |

<Npx>
drizzle-kit push dialect=mysql schema=src/schema.ts url=mysql://user:password@host:3306/dbname
drizzle-kit push dialect=mysql schema=src/schema.ts --tablesFilter='user*' url=mysql://user:password@host:3306/dbname
</Npx>


### Extended example
Let's declare drizzle schema in the project and push it to the database via `drizzle-kit push` command

```plaintext
📦 <project root>
 ├ 📂 src
 │ ├ 📜 schema.ts
 │ └ 📜 index.ts
 ├ 📜 drizzle.config.ts
 └ …
```
<CodeTabs items={["drizzle.config.ts", "src/schema.ts"]}>
```ts
import { defineConfig } from "drizzle-kit";

export default defineConfig({
  dialect: "mysql",
  schema: "./src/schema.ts",
  dbCredentials: {
    url: "mysql://user:password@host:3306/dbname"
  },
});
```
```ts 
import * as p from "drizzle-orm/mysql-core";

export const users = p.mysqlTable("users", {
  id: p.int().primaryKey().autoincrement(),
  name: p.varchar({ length: 255 }),
})
```
</CodeTabs>

Now let's run
```shell
npx drizzle-kit push
```

it will pull existing(empty) schema from the database and generate SQL migration and apply it under the hood
```sql
CREATE TABLE `users` (
 `id` int AUTO_INCREMENT PRIMARY KEY,
 `name` varchar(255)
);
```

DONE ✅


Source: https://orm.drizzle.team/docs/mysql/drizzle-kit-studio

import CodeTab from "@mdx/CodeTab.astro";
import CodeTabs from "@mdx/CodeTabs.astro";
import Section from "@mdx/Section.astro";
import Tab from "@mdx/Tab.astro";
import Tabs from "@mdx/Tabs.astro";
import Callout from "@mdx/Callout.astro";
import Prerequisites from "@mdx/Prerequisites.astro";
import Npm from "@mdx/Npm.astro";
import Npx from "@mdx/Npx.astro";


# `drizzle-kit studio`
<Prerequisites>
- Drizzle Kit [overview](/docs/mysql/kit-overview) and [config file](/docs/mysql/drizzle-config-file)
- Drizzle Studio, our database browser - [read here](/drizzle-studio/overview)
</Prerequisites>

`drizzle-kit studio` command spins up a server for [Drizzle Studio](/drizzle-studio/overview) hosted on [local.drizzle.studio](https://local.drizzle.studio). 
It requires you to specify database connection credentials via [drizzle.config.ts](/docs/mysql/drizzle-config-file) config file.

By default it will start a Drizzle Studio server on `127.0.0.1:4983`
<Section>
```ts {6}
// drizzle.config.ts
import { defineConfig } from "drizzle-kit";

export default defineConfig({
  dialect: "mysql",
  dbCredentials: {
    url: "mysql://user:password@host:3306/dbname"
  },
});
```
```shell
npx drizzle-kit studio
```
</Section>

### Configuring `host` and `port`
By default Drizzle Studio server starts on `127.0.0.1:4983`, 
you can config `host` and `port` via CLI options

<Npx>
drizzle-kit studio --port=3000
drizzle-kit studio --host=0.0.0.0
drizzle-kit studio --host=0.0.0.0 --port=3000
</Npx>


### Logging
You can enable logging of every SQL statement by providing `verbose` flag

<Npx>
drizzle-kit studio --verbose
</Npx>

### Safari and Brave support
Safari and Brave block access to localhost by default. 
You need to install [mkcert](https://github.com/FiloSottile/mkcert) and generate self-signed certificate:

1. Follow the mkcert [installation steps](https://github.com/FiloSottile/mkcert#installation)
2. Run `mkcert -install`
3. Restart your `drizzle-kit studio`

### Other flavours of Drizzle Studio
Apart from `drizzle-kit studio` for local development, Drizzle Studio also comes as a self-hosted
Drizzle Gateway, a Chrome extension for serverless database vendors and an embeddable component
for your own product — check out the [Drizzle Studio overview](/drizzle-studio/overview).

### Limitations
Our hosted version Drizzle Studio is meant to be used for local development and not meant to be used on remote (VPS, etc).

If you want to deploy Drizzle Studio to your VPS — that's what
[Drizzle Gateway](/drizzle-studio/overview#drizzle-gateway) is for.

### Is it open source?
No. Drizzle ORM and Drizzle Kit are fully open sourced, while Studio is not. 

Drizzle Studio for local development is free to use forever to enrich Drizzle ecosystem, 
open sourcing one would've break our ability to provide B2B offerings and monetise it, unfortunately.


Source: https://orm.drizzle.team/docs/mysql/drizzle-kit-up

import CodeTab from "@mdx/CodeTab.astro";
import CodeTabs from "@mdx/CodeTabs.astro";
import Section from "@mdx/Section.astro";
import Tab from "@mdx/Tab.astro";
import Tabs from "@mdx/Tabs.astro";
import Callout from "@mdx/Callout.astro";
import Prerequisites from "@mdx/Prerequisites.astro";
import Npx from "@mdx/Npx.astro";
import Dialects from "@mdx/Dialects.mdx"

# `drizzle-kit up`

<Prerequisites>
- Get started with Drizzle and `drizzle-kit` - [read here](/docs/mysql/get-started)
- Drizzle schema fundamentals - [read here](/docs/mysql/sql-schema-declaration)
- Database connection basics - [read here](/docs/mysql/connect-overview)
- Drizzle migrations fundamentals - [read here](/docs/mysql/migrations)
- Drizzle Kit [overview](/docs/mysql/kit-overview) and [config file](/docs/mysql/drizzle-config-file)
- `drizzle-kit generate` command - [read here](/docs/mysql/drizzle-kit-generate)
</Prerequisites>

`drizzle-kit up` command lets you upgrade drizzle schema snapshots to a newer version. 
It's required whenever we introduce breaking changes to the json snapshots of the schema and upgrade the internal version.

<br/>
<hr/>
<br/>

`drizzle-kit up` command requires you to specify `dialect` param, 
you can provide it either via [drizzle.config.ts](/docs/mysql/drizzle-config-file) config file or via CLI options

<CodeTabs items={["With config file", "As CLI options"]}>
<Section>
```ts {5,8}
// drizzle.config.ts
import { defineConfig } from "drizzle-kit";

export default defineConfig({
  dialect: "mysql",
});
```
```shell
npx drizzle-kit up
```
</Section>
```shell
npx drizzle-kit up --dialect=mysql
```
</CodeTabs>

### Multiple configuration files in one project
You can have multiple config files in the project, it's very useful when you have multiple database stages or multiple databases on the same project:
<Npx>
  drizzle-kit migrate --config=drizzle-dev.config.ts
  drizzle-kit migrate --config=drizzle-prod.config.ts
</Npx>
```plaintext {5-6}
📦 <project root>
 ├ 📂 drizzle
 ├ 📂 src
 ├ 📜 .env
 ├ 📜 drizzle-dev.config.ts
 ├ 📜 drizzle-prod.config.ts
 ├ 📜 package.json
 └ 📜 tsconfig.json
```

### Extended list of configurations
We recommend configuring `drizzle-kit` through [drizzle.config.ts](/docs/mysql/drizzle-config-file) file, 
yet you can provide all configuration options through CLI if necessary, e.g. in CI/CD pipelines, etc.
<rem025/>
|           |            |                                                                         |
| :-------- | :--------- | :---------------------------------------------------------------------- |
| `dialect` | `required` | Database dialect you are using. Can be <Dialects/> |
| `out`     |            | Migrations folder, default=`./drizzle`                                  |
| `config`  |            | Configuration file path, default=`drizzle.config.ts`                           |
<br/>
<Npx>
drizzle-kit up --dialect=mysql
drizzle-kit up --dialect=mysql --out=./migrations-folder
</Npx>

{/* TODO update gifs */}
![](@/assets/gifs/up_mysql.gif)


Source: https://orm.drizzle.team/docs/mysql/dynamic-query-building

import Callout from '@mdx/Callout.astro';

# Dynamic query building

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
```

In the previous ORM versions, when such restrictions weren't implemented, this example in particular was a source of confusion for many users, as they expected the query builder to "merge" multiple `.where()` calls into a single condition.

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 MySqlSelect>(
	qb: T,
	page: number = 1,
	pageSize: number = 10,
) {
  return qb.limit(pageSize).offset((page - 1) * 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 MySqlSelect>(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);
```

This is possible, because `MySqlSelect` and other similar types are specifically designed to be used in dynamic query building. They can only be used in dynamic mode.

Here is the list of all types that can be used as generic parameters in dynamic query building:

| Query  | Type                                          |
|:-------|:----------------------------------------------|
| Select | `MySqlSelect` / `MySqlSelectQueryBuilder`     |
| Insert | `MySqlInsert`                                 |
| Update | `MySqlUpdate`                                 |
| Delete | `MySqlDelete`                                 |

<Callout type='info'>
	The `...QueryBuilder` types are for usage with [standalone query builder
	instances](/docs/mysql/goodies#standalone-query-builder). DB query builders are
	subclasses of them, so you can use them as well.

    ```ts
    	import { QueryBuilder } from 'drizzle-orm/mysql-core';

    	function withFriends<T extends MySqlSelectQueryBuilder>(qb: T) {
    		return qb.leftJoin(friends, eq(friends.userId, users.id));
    	}

    	const qb = new QueryBuilder();
    	let query = qb.select().from(users).where(eq(users.id, 1)).$dynamic();
    	query = withFriends(query);
    ```

</Callout>


Source: https://orm.drizzle.team/docs/mysql/effect-schema

import Npm from '@mdx/Npm.astro';
import Callout from '@mdx/Callout.astro';

# effect-schema

Allows you to generate [effect](https://effect.website/) schemas from Drizzle ORM schemas.

**Features**

- Create a select schema for tables and views.
- Create insert and update schemas for tables.
- Supported dialect: MySQL.

#### Usage

```ts
import { int, mysqlTable, text, timestamp } from 'drizzle-orm/mysql-core';
import { createInsertSchema, createSelectSchema, createUpdateSchema } from 'drizzle-orm/effect-schema';
import { Effect, Schema } from "effect";

const users = mysqlTable('users', {
	id: int().primaryKey().autoincrement(),
	name: text().notNull(),
	email: text().notNull(),
	role: text({ enum: ['admin', 'user'] }).notNull(),
	createdAt: timestamp('created_at').notNull().defaultNow(),
});

// Schema for inserting a user - can be used to validate API requests
const UserInsert = createInsertSchema(users);

// Schema for updating a user - can be used to validate API requests
const UserUpdate = createUpdateSchema(users);

// Schema for selecting a user - can be used to validate API responses
const UserSelect = createSelectSchema(users);

// Overriding the fields
const UserInsert = createInsertSchema(users, {
	role: Schema.String,
});

// Refining the fields - useful if you want to change the fields before they become nullable/optional in the final schema
const UserInsert = createInsertSchema(users, {
	id: (schema) => schema.check(Schema.isGreaterThanOrEqualTo(0)),
	role: Schema.String,
});

// Usage
const program = Effect.gen(function*() {
	const parsedUser = yield* Schema.decodeUnknownEffect(UserInsert)({
		name: 'John Doe',
		email: 'johndoe@test.com',
		role: 'admin',
	});
});
```

Source: https://orm.drizzle.team/docs/mysql/extensions


import Callout from '@mdx/Callout.astro';

<Callout>
Currently, there are no MySQL extensions natively supported by Drizzle. Once those are added, we will have them here!
</Callout>

Source: https://orm.drizzle.team/docs/mysql/generated-columns

import CodeTabs from '@mdx/CodeTabs.astro';
import CodeTab from '@mdx/CodeTab.astro';
import Callout from '@mdx/Callout.astro';

# Generated Columns

1. Virtual (or non-persistent) Generated Columns: These columns are computed dynamically whenever they are queried. They do not occupy storage space in the database.

2. Stored (or persistent) Generated Columns: These columns are computed when a row is inserted or updated and their values are stored in the database. This allows them to be indexed and can improve query performance since the values do not need to be recomputed for each query.

#### Database side
    **Types**: `VIRTUAL`, `STORED`

	When no type is specified, `VIRTUAL` is used by default

    **How It Works**
    - Defined with an expression in the table schema.
    - Virtual columns are computed during read operations.
    - Stored columns are computed during write operations and stored.

    **Capabilities**
    - Used in SELECT, INSERT, UPDATE, and DELETE statements.
    - Can be indexed, both virtual and stored.
    - Can specify NOT NULL and other constraints.
    
    **Limitations**
    - Cannot directly insert or update values in a generated column 

    For more info, please check [MySQL Alter Generated](https://dev.mysql.com/doc/refman/8.4/en/alter-table-generated-columns.html) docs and [MySQL create generated](https://dev.mysql.com/doc/refman/8.4/en/create-table-generated-columns.html) docs

    #### Drizzle side
    In Drizzle you can specify `.generatedAlwaysAs()` function on any column type and add a supported sql query, 
    that will generate this column data for you.

    #### Features 
    This function can accept generated expression in 2 ways:

    **`sql`** tag - if you want drizzle to escape some values for you

    <CodeTab>
    ```ts {2,6}
    export const test_1 = mysqlTable("test_1", {
      generatedName: text("gen_name").generatedAlwaysAs(sql`'hello "world"!'`),
    });
    
    export const test_2 = mysqlTable("test_2", {
      generatedName: text("gen_name").generatedAlwaysAs(sql`'hello "world"!'`, { mode: "stored" }),
    });
    ```
    ```sql {2,6}
    CREATE TABLE `test_1` (
        `gen_name` text GENERATED ALWAYS AS ('hello "world"!') VIRTUAL
    );
    
    CREATE TABLE `test_2` (
        `gen_name` text GENERATED ALWAYS AS ('hello "world"!') STORED
    );
    ```
    </CodeTab>

    **`callback`** - if you need to reference columns from a table

     <CodeTab>
    ```ts {4,10}
    export const test_1 = mysqlTable("test_1", {
      name: text("first_name"),
      generatedName: text("gen_name")
	     .generatedAlwaysAs((): SQL => sql`concat('hi, ', ${test_1.name}, '!')`),
    });
    
    export const test_2 = mysqlTable("test_2", {
      name: text("first_name"),
      generatedName: text("gen_name")
	     .generatedAlwaysAs((): SQL => sql`concat('hi, ', ${test_2.name}, '!')`, { mode: "stored" }),
    });
    ```
    ```sql {3,8}
    CREATE TABLE `test_1` (
        `first_name` text,
        `gen_name` text GENERATED ALWAYS AS (concat('hi, ', `test_1`.`first_name`, '!')) VIRTUAL
    );
    
    CREATE TABLE `test_2` (
        `first_name` text,
        `gen_name` text GENERATED ALWAYS AS (concat('hi, ', `test_2`.`first_name`, '!')) STORED
    );
    ```
    </CodeTab>

    #### Limitations
    Drizzle Kit will also have limitations for `push` command:
    1. You can't change the generated constraint expression and type using `push`. Drizzle-kit will ignore this change. To make it work, you would need to `drop the column`, `push`, and then `add a column with a new expression`. This was done due to the complex mapping from the database side, where the schema expression will be modified on the database side and, on introspection, we will get a different string. We can't be sure if you changed this expression or if it was changed and formatted by the database. As long as these are generated columns and `push` is mostly used for prototyping on a local database, it should be fast to `drop` and `create` generated columns. Since these columns are `generated`, all the data will be restored
    2. `generate` should have no limitations

  <CodeTabs items={["schema.ts"]}>
	<CodeTab>
	```typescript copy
    export const users = mysqlTable("users", {
        id: int(),
        id2: int(),
        name: text(),
        storedGenerated: text("stored_gen").generatedAlwaysAs(
          (): SQL => sql`concat(${users.name}, ' ', 'hello')`,
          { mode: "stored" }
        ),
        virtualGenerated: text("virtual_gen").generatedAlwaysAs(
          (): SQL => sql`concat(${users.name}, ' ', 'hello')`,
          { mode: "virtual" }
        ),
    });
    ```
    ```sql
    CREATE TABLE `users` (
      `id` int,
      `id2` int,
      `name` text,
      `stored_gen` text GENERATED ALWAYS AS (concat(`users`.`name`, ' ', 'hello')) STORED,
      `virtual_gen` text GENERATED ALWAYS AS (concat(`users`.`name`, ' ', 'hello')) VIRTUAL
    );
    ```
    </CodeTab>
  </CodeTabs>


Source: https://orm.drizzle.team/docs/mysql/get-started-mysql

import Npm from '@mdx/Npm.astro';
import Callout from '@mdx/Callout.astro';
import Prerequisites from "@mdx/Prerequisites.astro";
import CodeTabs from "@mdx/CodeTabs.astro";
import WhatsNextMySQL from "@mdx/WhatsNextMySQL.astro";

# Drizzle \<\> MySQL

To use Drizzle with a MySQL database, you should use the `mysql2` driver

According to the **[official website](https://github.com/sidorares/node-mysql2)**, 
`mysql2` is a MySQL client for Node.js with focus on performance.  

Drizzle ORM natively supports `mysql2` with `drizzle-orm/mysql2` package.

#### Step 1 - Install packages
<Npm>
 drizzle-orm@rc mysql2
 -D drizzle-kit@rc
</Npm>

#### Step 2 - Initialize the driver and make a query
<CodeTabs items={['mysql2', 'mysql with config']}>
```typescript copy
import { drizzle } from "drizzle-orm/mysql2";

const db = drizzle(process.env.DATABASE_URL);

const response = await db.select().from(...)
```
```typescript copy
import { drizzle } from "drizzle-orm/mysql2";

// You can specify any property from the mysql2 connection options
const db = drizzle({ connection:{ uri: process.env.DATABASE_URL }});

const response = await db.select().from(...)
```
</CodeTabs>

If you need to provide your existing driver:

<CodeTabs items={['Client connection', 'Pool connection']}>
  ```typescript copy
  import { drizzle } from "drizzle-orm/mysql2";
  import mysql from "mysql2/promise";

  const connection = await mysql.createConnection({
    host: "host",
    user: "user",
    database: "database",
    ...
  });

  const db = drizzle({ client: connection });
  ```
  ```typescript copy
  import { drizzle } from "drizzle-orm/mysql2";
  import mysql from "mysql2/promise";

  const poolConnection = mysql.createPool({
    host: "host",
    user: "user",
    database: "database",
    ...
  });

  const db = drizzle({ client: poolConnection });
  ```
</CodeTabs>

<Callout type="warning" emoji="⚙️">
  For the built in `migrate` function with DDL migrations we and drivers strongly encourage you to use single `client` connection.  

  For querying purposes feel free to use either `client` or `pool` based on your business demands.
</Callout>

#### What's next?

<WhatsNextMySQL/>


Source: https://orm.drizzle.team/docs/mysql/goodies


import Callout from '@mdx/Callout.astro';
import CodeTabs from '@mdx/CodeTabs.astro';

## Type API
To retrieve a type from your table schema for `select` and `insert` queries, you can make use of our type helpers.

```ts
import { int, text, mysqlTable } from 'drizzle-orm/mysql-core';
import { type InferSelectModel, type InferInsertModel } from 'drizzle-orm'

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

type SelectUser = typeof users.$inferSelect;
type InsertUser = typeof users.$inferInsert;
// or
type SelectUser = InferSelectModel<typeof users>;
type InsertUser = InferInsertModel<typeof users>;
```


## Logging
To enable default query logging, just pass `{ logger: true }` to the `drizzle` initialization function:
```typescript copy
import { drizzle } from 'drizzle-orm/mysql2';

const db = drizzle({ logger: true });
```

You can change the logs destination by creating a `DefaultLogger` instance and providing a custom `writer` to it:
```typescript copy
import { DefaultLogger, type LogWriter } from "drizzle-orm/logger";
import { drizzle } from "drizzle-orm/mysql2";

class MyLogWriter implements LogWriter {
  write(message: string) {
    // Write to file, stdout, etc.
  }
}

const logger = new DefaultLogger({ writer: new MyLogWriter() });
const db = drizzle(process.env.DB_URL, { logger });
```

You can also create a custom logger:
```typescript copy
import { type Logger } from 'drizzle-orm/logger';
import { drizzle } from 'drizzle-orm/mysql2';

class MyLogger implements Logger {
  logQuery(query: string, params: unknown[]): void {
    console.log({ query, params });
  }
}

const db = drizzle(process.env.DB_URL, { logger: new MyLogger() });
```


## Multi-project schema
**Table creator** API lets you define customize table names.  
It's very useful when you need to keep schemas of different projects in one database.

```ts {3}
import { int, text, mysqlTableCreator } from 'drizzle-orm/mysql-core';

const mysqlTable = mysqlTableCreator((name) => `project1_${name}`);

export const users = mysqlTable('users', {
  id: int().primaryKey(),
  name: text().notNull(),
});
```
```ts {10}
import { defineConfig } from "drizzle-kit";

export default defineConfig({
  schema: "./src/schema/*",
  out: "./drizzle",
  dialect: "mysql", 
  dbCredentials: {
    url: process.env.DATABASE_URL,
  }
  tablesFilter: ["project1_*"],
});
```

You can apply multiple `or` filters:
```ts
tablesFilter: ["project1_*", "project2_*"]
```


## Printing SQL query
You can print SQL queries with `db` instance or by using **[`standalone query builder`](#standalone-query-builder)**.
```typescript copy
const query = db
  .select({ id: users.id, name: users.name })
  .from(users)
  .groupBy(users.id)
  .toSQL();
// query:
{
  sql: 'select `id`, `name` from `users` group by `users`.`id`',
  params: [],
}
```

## Raw SQL 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 `parametrized` queries.

```typescript copy
import { ..., type MySqlRawQueryResult } from "drizzle-orm/mysql2";

const userId = 11;
const statement = sql`select * from ${users} where ${users.id} = ${userId}`;

const res: MySqlRawQueryResult = await db.execute(statement);
```


## Standalone query builder
Drizzle ORM provides a standalone query builder that allows you to build queries
without creating a database instance and get generated SQL.
```typescript copy
import { QueryBuilder } from 'drizzle-orm/mysql-core';

const qb = new QueryBuilder();

const query = qb.select().from(users).where(eq(users.name, 'Dan'));
const { sql, params } = query.toSQL();
```

## Get typed columns
You can get a typed columns map,
very useful when you need to omit certain columns upon selection.

<CodeTabs items={["index.ts", "schema.ts"]}>
  ```ts
  import { getColumns } from "drizzle-orm";
  import { user } from "./schema";

  const { password, role, ...rest } = getColumns(user);

  await db.select({ ...rest }).from(user);
  ```
  ```ts
  import { int, text, mysqlTable } from "drizzle-orm/mysql-core";

  export const user = mysqlTable("user", {
    id: int().primaryKey().autoincrement(),
    name: text(),
    email: text(),
    password: text(),
    role: text().$type<"admin" | "customer">(),
  });
  ```
</CodeTabs>

## Get table information
```ts copy
import { getTableConfig, mysqlTable } from 'drizzle-orm/mysql-core';

export const table = mysqlTable(...);

const {
  columns,
  indexes,
  foreignKeys,
  checks,
  primaryKeys,
  name,
  schema,
} = getTableConfig(table);
```

## Compare objects types (instanceof alternative)

You can check if an object is of a specific Drizzle type using the `is()` function. 
You can use it with any available type in Drizzle.

<Callout type="warning" emoji="⭐️">
  You should always use `is()` instead of `instanceof`
</Callout>

**Few examples**
```ts
import { Column, is } from 'drizzle-orm';

if (is(value, Column)) {
  // value's type is narrowed to Column
}
```

### Mock Driver
This API is a successor to an undefined `drizzle({} as any)` API which we've used internally in Drizzle tests and rarely recommended to external developers. 

We decided to build and expose a proper API, every `drizzle` driver now has `drizzle.mock()`:
```ts
import { drizzle } from "drizzle-orm/mysql2";

const db = drizzle.mock();
```

you can provide schema if necessary for types
```ts
import { drizzle } from "drizzle-orm/mysql2";
import { relations } from "./relations"

const db = drizzle.mock({ relations  });
```


Source: https://orm.drizzle.team/docs/mysql/guides/count-rows

import Section from "@mdx/Section.astro";
import Prerequisites from "@mdx/Prerequisites.astro";
import CodeTabs from '@mdx/CodeTabs.astro';
import CodeTab from '@mdx/CodeTab.astro';
import Callout from '@mdx/Callout.astro';

<Prerequisites>
- Get started with [MySQL](/docs/mysql/get-started-mysql)
- [Select statement](/docs/mysql/select)
- [Filters](/docs/mysql/operators) and [sql operator](/docs/mysql/sql)
- [Aggregations](/docs/mysql/select#aggregations) and [Aggregation helpers](/docs/mysql/select#aggregations-helpers)
- [Joins](/docs/mysql/joins)
</Prerequisites>

To count all rows in table you can use `count()` function or `sql` operator like below:

<CodeTabs items={["index.ts", "schema.ts"]}>
  <CodeTab>
    ```ts copy {6,9}
    import { count, sql } from 'drizzle-orm';
    import { products } from './schema';

    const db = drizzle(...);

    await db.select({ count: count() }).from(products);

    // Under the hood, the count() function casts its result to a number at runtime.
    await db.select({ count: sql`count(*)`.mapWith(Number) }).from(products);
    ```

    ```ts
    // result type
    type Result = {
      count: number;
    }[];
    ```

    ```sql
    select count(*) from products;
    ```
  </CodeTab>
  ```ts
  import { int, mysqlTable, varchar } from 'drizzle-orm/mysql-core';

  export const products = mysqlTable('products', {
    id: int('id').primaryKey().autoincrement(),
    name: varchar('name', { length: 255 }).notNull(),
    discount: int('discount'),
    price: int('price').notNull(),
  });
  ```
</CodeTabs>

To count rows where the specified column contains non-NULL values you can use `count()` function with a column:

<Section>
```ts copy {1}
await db.select({ count: count(products.discount) }).from(products);
```

```ts
// result type
type Result = {
  count: number;
}[];
```

```sql
select count(`discount`) from products;
```
</Section>

Drizzle has simple and flexible API, which lets you create your custom solutions. In MySQL, `count()` can be returned as a string by the driver, so cast it to a number when you need a numeric result:

<Section>
```ts copy {5,7,11,12}
import { AnyColumn, sql } from 'drizzle-orm';

const customCount = (column?: AnyColumn) => {
  if (column) {
    return sql<number>`cast(count(${column}) as unsigned)`; // In MySQL cast to unsigned integer
  } else {
    return sql<number>`cast(count(*) as unsigned)`; // In MySQL cast to unsigned integer
  }
};

await db.select({ count: customCount() }).from(products);
await db.select({ count: customCount(products.discount) }).from(products);
```

```sql
select cast(count(*) as unsigned) from products;
select cast(count(`discount`) as unsigned) from products;
```
</Section>


<Callout type="warning">
By specifying `sql<number>`, you are telling Drizzle that the **expected** type of the field is `number`.<br />
If you specify it incorrectly (e.g. use `sql<string>` for a field that will be returned as a number), the runtime value won't match the expected type.
Drizzle cannot perform any type casts based on the provided type generic, because that information is not available at runtime.

If you need to apply runtime transformations to the returned value, you can use the [`.mapWith()`](/docs/mysql/sql#sqlmapwith) method.
</Callout>

To count rows that match a condition you can use `.where()` method:

<Section>
```ts copy {4,6}
import { count, gt } from 'drizzle-orm';

await db
  .select({ count: count() })
  .from(products)
  .where(gt(products.price, 100));
```

```sql
select count(*) from products where price > 100
```
</Section>

This is how you can use `count()` function with joins and aggregations:

<CodeTabs items={["index.ts", "schema.ts"]}>
	<CodeTab>
    ```ts copy {8,11,12,13}
    import { count, eq } from 'drizzle-orm';
    import { countries, cities } from './schema';

    // Count cities in each country
    await db
      .select({
        country: countries.name,
        citiesCount: count(cities.id),
      })
      .from(countries)
      .leftJoin(cities, eq(countries.id, cities.countryId))
      .groupBy(countries.id)
      .orderBy(countries.name);
    ```

    ```sql
    select countries.name, count(`cities`.`id`) from countries
      left join cities on countries.id = cities.country_id
      group by countries.id
      order by countries.name;
    ```
  </CodeTab>
  ```ts
  import { int, mysqlTable, varchar } from 'drizzle-orm/mysql-core';

  export const countries = mysqlTable('countries', {
    id: int('id').primaryKey().autoincrement(),
    name: varchar('name', { length: 255 }).notNull(),
  });

  export const cities = mysqlTable('cities', {
    id: int('id').primaryKey().autoincrement(),
    name: varchar('name', { length: 255 }).notNull(),
    countryId: int('country_id').notNull().references(() => countries.id),
  });
  ```
</CodeTabs>


Source: https://orm.drizzle.team/docs/mysql/indexes-constraints

import Callout from '@mdx/Callout.astro';
import Section from '@mdx/Section.astro';

# Indexes & Constraints

## Constraints

SQL constraints are the rules enforced on table columns. They are used to prevent invalid data from being entered into the database.

This ensures the accuracy and reliability of your data in the database.

### Default

The `DEFAULT` clause specifies a default value to use for the column if no value provided by the user when doing an `INSERT`.
If there is no explicit `DEFAULT` clause attached to a column definition,
then the default value of the column is `NULL`.

An explicit `DEFAULT` clause may specify that the default value is `NULL`,
a string constant, a blob constant, a signed-number, or any constant expression enclosed in parentheses.

<Section>
    ```typescript
    import { sql } from "drizzle-orm";
    import { int, time, mysqlTable } from "drizzle-orm/mysql-core";
    
    export const table = mysqlTable("table", {
      int: int().default(42),
      time: time().default(sql`cast("14:06:10" AS TIME)`),
    });
    ```
    ```sql
	CREATE TABLE `table` (
	  `int` int DEFAULT 42,
	  `time` time DEFAULT (cast("14:06:10" AS TIME))
	);
    ```
    </Section>

### Not null

By default, a column can hold **NULL** values. The `NOT NULL` constraint enforces a column to **NOT** accept **NULL** values.  

This enforces a field to always contain a value, which means that you cannot insert a new record,
or update a record without adding a value to this field.

<Section>
      ```typescript
      import { int, mysqlTable } from "drizzle-orm/mysql-core";

      export const table = mysqlTable('table', {
        int: int().notNull(),
      });
      ```

      ```sql
      CREATE TABLE `table` (
        `int` int NOT NULL
      );
      ```
    </Section>

### Unique

The `UNIQUE` constraint ensures that all values in a column are different.  

Both the `UNIQUE` and `PRIMARY KEY` constraints provide a guarantee for uniqueness for a column or set of columns.

A `PRIMARY KEY` constraint automatically has a `UNIQUE` constraint.  

<Callout type="info" emoji="ℹ️">
  You can have many `UNIQUE` constraints per table, but only one `PRIMARY KEY` constraint per table.
</Callout>

In MySQL, a `unique constraint` and a `unique index` are essentially the same thing.  
Under the hood, MySQL implements a unique constraint as a unique index. 
There is no separate constraint object like you might find in some other databases.
```sql
-- These three all produce the exact same result in MySQL:
ALTER TABLE users ADD CONSTRAINT uq_email UNIQUE (email);
ALTER TABLE users ADD UNIQUE INDEX uq_email (email);
CREATE UNIQUE INDEX uq_email ON users(email);
```

To drop a `unique constraint`, the same syntax is used as dropping an index: `ALTER TABLE users DROP INDEX uq_email;`. There's no separate `DROP CONSTRAINT statement` for it in MySQL.

That is why Drizzle always treats any `.unique()` as `UNIQUE INDEX`

<Section>
      ```typescript
      import { int, varchar, unique, mysqlTable } from "drizzle-orm/mysql-core";

      export const user = mysqlTable('user', {
        id: int().unique(),
      });

      export const table = mysqlTable('table', {
        id: int().unique('custom_name'),
      });

      export const composite = mysqlTable('composite_example', {
        id: int(),
        name: varchar(, { length: 256 }),
      }, (t) => [
        unique().on(t.id, t.name),
        unique('custom_name').on(t.id, t.name)
      ]);
      ```

      ```sql
	CREATE TABLE `user` (
	  `id` int,
	  CONSTRAINT `id_unique` UNIQUE INDEX(`id`)
	);

	CREATE TABLE `table` (
	  `id` int,
	  CONSTRAINT `custom_name` UNIQUE INDEX(`id`)
	);

	CREATE TABLE `composite_example` (
	  `id` int,
	  `name` varchar(256),
	  CONSTRAINT `id_name_unique` UNIQUE INDEX(`id`,`name`),
	  CONSTRAINT `custom_name` UNIQUE INDEX(`id`,`name`)
	);
      ```
    </Section>

### Check

The `CHECK` constraint is used to limit the value range that can be placed in a column.

If you define a `CHECK` constraint on a column it will allow only certain values for this column.  

If you define a `CHECK` constraint on a table it can limit the values in certain columns based on values in other columns in the row.

<Section>
      ```typescript copy
      import { sql } from "drizzle-orm";
      import { check, int, mysqlTable, text } from "drizzle-orm/mysql-core";

      export const users = mysqlTable(
        "users",
        {
          id: int().primaryKey(),
          username: text().notNull(),
          age: int(),
        },
        (table) => [
          check("age_check1", sql`${table.age} > 21`)
        ]
      );
      ```
      ```sql
	  CREATE TABLE `users` (
	    `id` int PRIMARY KEY,
	    `username` text NOT NULL,
	    `age` int,
	    CONSTRAINT `age_check1` CHECK(`users`.`age` > 21)
	  );
      ```
    </Section>

### Primary Key

The `PRIMARY KEY` constraint uniquely identifies each record in a table.  
Primary keys must contain `UNIQUE` values, and cannot contain `NULL` values.  

A table can have only **ONE** primary key; and in the table, this primary key can consist of single or multiple columns (fields).

<Section>
      ```typescript
      import { int, text, mysqlTable } from "drizzle-orm/mysql-core";

      export const user = mysqlTable("user", {
        id: int().autoincrement().primaryKey(),
      })

      export const table = mysqlTable("table", {
        cuid: text().primaryKey(),
      })
      ```

      ```sql
	  CREATE TABLE `user` (
	    `id` int AUTO_INCREMENT PRIMARY KEY
	  );

	  CREATE TABLE `table` (
	    `cuid` text PRIMARY KEY
	  );
      ```
    </Section>

### Composite Primary Key

Just like `PRIMARY KEY`, composite primary key uniquely identifies each record in a table using multiple fields.

Drizzle ORM provides a standalone `primaryKey` operator for that:

<Section>
      ```typescript {18, 19}
      import { int, text, primaryKey, mysqlTable } from "drizzle-orm/mysql-core";

      export const user = mysqlTable("user", {
        id: int("id").autoincrement().primaryKey(),
        name: text("name"),
      });

      export const book = mysqlTable("book", {
        id: int().autoincrement().primaryKey(),
        name: text(),
      });

      export const booksToAuthors = mysqlTable("books_to_authors", {
        authorId: int(),
        bookId: int(),
      }, (table) => [
        primaryKey({ columns: [table.bookId, table.authorId] }),
        // Or PK with custom name
        primaryKey({ name: 'custom_name', columns: [table.bookId, table.authorId] })
      ]);
      ```

      ```sql {6}
      ...

      CREATE TABLE `books_to_authors` (
        `author_id` int,
        `book_id` int,
        PRIMARY KEY(`book_id`,`author_id`)
      );
      ```
    </Section>

### Foreign key

The `FOREIGN KEY` constraint is used to prevent actions that would destroy links between tables.
A `FOREIGN KEY` is a field (or collection of fields) in one table, that refers to the `PRIMARY KEY` in another table.
The table with the foreign key is called the child table, and the table with the primary key is called the referenced or parent table.

Drizzle ORM provides several ways to declare foreign keys.
You can declare them in a column declaration statement:

	```typescript {11}
    import { int, text, mysqlTable } from "drizzle-orm/mysql-core";

    export const user = mysqlTable("user", {
      id: int().primaryKey().autoincrement(),
      name: text(),
    });

    export const book = mysqlTable("book", {
      id: int().primaryKey().autoincrement(),
      name: text(),
      authorId: int("author_id").references(() => user.id)
    });
    ```

If you want to do a self reference, due to a TypeScript limitations you will have to either explicitly
set return type for reference callback or use a standalone `foreignKey` operator.

	```typescript {6,15-19}
    import { int, text, foreignKey, type AnyMySqlColumn, mysqlTable } from "drizzle-orm/mysql-core";

    export const user = mysqlTable("user", {
      id: int().primaryKey().autoincrement(),
      name: text(),
      parentId: int("parent_id").references((): AnyMySqlColumn => user.id),
    });

    // or
    export const user = mysqlTable("user", {
      id: int().primaryKey().autoincrement(),
      name: text(),
      parentId: int("parent_id")
    }, (table) => [
      foreignKey({
        columns: [table.parentId],
        foreignColumns: [table.id],
        name: "custom_fk"
      })
    ]);
    ```

To declare multi-column foreign keys you can use a dedicated `foreignKey` operator:

	```typescript copy {4-5,7,15-19}
    import { int, text, primaryKey, foreignKey, mysqlTable, type AnyMySqlColumn } from "drizzle-orm/mysql-core";

    export const user = mysqlTable("user", {
      firstName: text("firstName"),
      lastName: text("lastName"),
    }, (table) => [
      primaryKey({ columns: [table.firstName, table.lastName]})
    ]);

    export const profile = mysqlTable("profile", {
      id: int().autoincrement().primaryKey(),
      userFirstName: text("user_first_name"),
      userLastName: text("user_last_name"),
    }, (table) => [
      foreignKey({
        columns: [table.userFirstName, table.userLastName],
        foreignColumns: [user.firstName, user.lastName],
        name: "custom_name"
      })
    ]);
    ```

## Indexes

Drizzle ORM provides API for both `index` and `unique index` declaration:

<Section>
    ```typescript copy {8-9}
    import { int, text, index, uniqueIndex, mysqlTable } from "drizzle-orm/mysql-core";

    export const user = mysqlTable("user", {
      id: int("id").primaryKey().autoincrement(),
      name: text("name"),
      email: text("email"),
    }, (table) => [
      index("name_idx").on(table.name),
      uniqueIndex("email_idx").on(table.email),
    ]);
    ```
    ```sql {5-6}
    CREATE TABLE `user` (
      ...
    );

    CREATE INDEX `name_idx` ON `user` (`name`);
    CREATE UNIQUE INDEX `email_idx` ON `user` (`email`);
    ```
    </Section>

     Drizzle ORM provides set of all params for index creation:

    ```typescript
    // Index declaration reference
    index("name")
      .on(table.name)
      .algorithm("default") // "default" | "copy" | "inplace"
      .using("btree") // "btree" | "hash"
      .lock("default") // "none" | "default" | "exclusive" | "shared"
    ```


Source: https://orm.drizzle.team/docs/mysql/insert

import Section from '@mdx/Section.astro';
import Callout from '@mdx/Callout.astro';
import Tab from '@mdx/Tab.astro';
import Tabs from '@mdx/Tabs.astro';

# SQL Insert
Drizzle ORM provides you the most SQL-like way to insert rows into the database tables.

Inserting data with Drizzle is extremely straightforward and sql-like. See for yourself:

<Section>
```typescript copy 
await db.insert(users).values({ name: 'Andrew' });
```
```sql
insert into `users` (`name`) values ('Andrew');
```
</Section>

If you need insert type for a particular table you can use `typeof usersTable.$inferInsert` syntax. 
```typescript copy 
type NewUser = typeof users.$inferInsert;

const insertUser = async (user: NewUser) => {
  return db.insert(users).values(user);
}

const newUser: NewUser = { name: "Alef" };
await insertUser(newUser);
```

## $returningId
MySQL itself doesn't have native support for `RETURNING` after using `INSERT`. There is only one way to do it for `primary keys` with `autoincrement` (or `serial`) types, where you can access `insertId` and `affectedRows` fields. We've prepared an automatic way for you to handle such cases with Drizzle and automatically receive all inserted IDs as separate objects

```ts
import { boolean, int, text, mysqlTable } from 'drizzle-orm/mysql-core';

const usersTable = mysqlTable('users', {
  id: int().autoincrement().primaryKey(),
  name: text().notNull(),
  verified: boolean().notNull().default(false),
});


const result = await db.insert(usersTable).values([{ name: 'John' }, { name: 'John1' }]).$returningId();
//    ^? { id: number }[]
```

Also with Drizzle, you can specify a `primary key` with `$default` function that will generate custom primary keys at runtime. We will also return those generated keys for you in the `$returningId()` call

```ts
import { varchar, text, mysqlTable } from 'drizzle-orm/mysql-core';
import { createId } from '@paralleldrive/cuid2';

const usersTableDefFn = mysqlTable('users_default_fn', {
  customId: varchar({ length: 256 }).primaryKey().$defaultFn(createId),
  name: text().notNull(),
});


const result = await db.insert(usersTableDefFn).values([{ name: 'John' }, { name: 'John1' }]).$returningId();
//  ^? { customId: string }[]
```

> If there is no primary keys -> type will be `{}[]` for such queries

## Insert multiple rows
```typescript copy
await db.insert(users).values([{ name: 'Andrew' }, { name: 'Dan' }]);
```

## Upserts and conflicts
Drizzle ORM provides simple interfaces for handling upserts and conflicts.

### On duplicate key update
MySQL supports [`ON DUPLICATE KEY UPDATE`](https://dev.mysql.com/doc/refman/8.0/en/insert-on-duplicate.html) instead of `ON CONFLICT` clauses. MySQL will automatically determine the conflict target based on the primary key and unique indexes, and will update the row if *any* unique index conflicts.

Drizzle supports this through the `onDuplicateKeyUpdate` method:

```typescript
// Note that MySQL automatically determines targets based on the primary key and unique indexes
await db.insert(users)
  .values({ id: 1, name: 'John' })
  .onDuplicateKeyUpdate({ set: { name: 'John' } });
```

While MySQL does not directly support doing nothing on conflict, you can perform a no-op by setting any column's value to itself and achieve the same effect:

```typescript
import { sql } from 'drizzle-orm';

await db.insert(users)
  .values({ id: 1, name: 'John' })
  .onDuplicateKeyUpdate({ set: { id: sql`id` } });
```

## Insert into ... select

As the MySQL documentation mentions:

<Callout>
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
</Callout>

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


<Tabs items={["Query Builder", "Callback", "SQL template tag"]}>
<Tab>
<Section>
```ts
const insertedEmployees = await db
  .insert(employees)
  .select(
    db.select({ id: users.id, name: users.name }).from(users).where(eq(users.role, 'employee'))
  );
```
```ts
const qb = new QueryBuilder();
await db.insert(employees).select(
    qb.select({ id: users.id, name: users.name }).from(users).where(eq(users.role, 'employee'))
);
```
</Section>
</Tab>
<Tab>
<Section>
```ts
await db.insert(employees).select(
    () => db.select({ id: users.id, name: users.name }).from(users).where(eq(users.role, 'employee'))
);
```
```ts
await db.insert(employees).select(
    (qb) => qb.select({ id: users.id, name: users.name }).from(users).where(eq(users.role, 'employee'))
);
```
</Section>
</Tab>
<Tab>
<Section>
```ts
await db.insert(employees).select(
    sql`select users.id as id, users.name as name from users where users.role = 'employee'`
);
```
```ts
await db.insert(employees).select(
    () => sql`select users.id as id, users.name as name from users where users.role = 'employee'`
);
```
</Section>
</Tab>
</Tabs>


Source: https://orm.drizzle.team/docs/mysql/joins

import CodeTabs from '@mdx/CodeTabs.astro';
import CodeTab from '@mdx/CodeTab.astro';
import Section from '@mdx/Section.astro';

# Joins [SQL]
Join clause in SQL is used to combine 2 or more tables, based on related columns between them.
Drizzle ORM joins syntax is a balance between the SQL-likeness and type safety.

## Join types
Drizzle ORM has APIs for `INNER JOIN [LATERAL]`, `LEFT JOIN [LATERAL]`, `RIGHT JOIN`, and `CROSS JOIN [LATERAL]`.
Lets have a quick look at examples based on below table schemas:
```typescript copy
export const users = mysqlTable('users', {
  id: int().primaryKey().autoincrement(),
  name: varchar({ length: 255 }).notNull(),
  age: int(),
});

export const pets = mysqlTable('pets', {
  id: int().primaryKey().autoincrement(),
  name: varchar({ length: 255 }).notNull(),
  ownerId: int('owner_id').notNull().references(() => users.id),
})
```

### Left Join
<Section>
```typescript copy
const result = await db.select().from(users).leftJoin(pets, eq(users.id, pets.ownerId))
```
```sql
select ... from `users` left join `pets` on `users`.`id` = `pets`.`owner_id`
```
```typescript
// result type
const result: {
    users: {
        id: number;
        name: string;
        age: number | null;
    };
    pets: {
        id: number;
        name: string;
        ownerId: number;
    } | null;
}[];
```
</Section>

### Left Join Lateral
<Section>
```typescript copy
const subquery = db.select().from(pets).where(gte(users.age, 16)).as('userPets')
const result = await db.select().from(users).leftJoinLateral(subquery, sql`true`)
```
```sql
select ... from `users`
left join lateral (select ... from `pets` where `users`.`age` >= 16) `userPets` on true
```
```typescript
// result type
const result: {
    users: {
        id: number;
        name: string;
        age: number | null;
    };
    userPets: {
        id: number;
        name: string;
        ownerId: number;
    } | null;
}[];
```
</Section>

### Right Join
<Section>
```typescript copy
const result = await db.select().from(users).rightJoin(pets, eq(users.id, pets.ownerId))
```
```sql
select ... from `users` right join `pets` on `users`.`id` = `pets`.`owner_id`
```
```typescript
// result type
const result: {
    users: {
        id: number;
        name: string;
        age: number | null;
    } | null;
    pets: {
        id: number;
        name: string;
        ownerId: number;
    };
}[];
```
</Section>

### Inner Join
<Section>
```typescript copy
const result = await db.select().from(users).innerJoin(pets, eq(users.id, pets.ownerId))
```
```sql
select ... from `users` inner join `pets` on `users`.`id` = `pets`.`owner_id`
```
```typescript
// result type
const result: {
    users: {
        id: number;
        name: string;
        age: number | null;
    };
    pets: {
        id: number;
        name: string;
        ownerId: number;
    };
}[];
```
</Section>

### Inner Join Lateral
<Section>
```typescript copy
const subquery = db.select().from(pets).where(gte(users.age, 16)).as('userPets')
const result = await db.select().from(users).innerJoinLateral(subquery, sql`true`)
```
```sql
select ... from `users` inner join lateral (select ... from `pets` where `users`.`age` >= 16) `userPets` on true
```
```typescript
// result type
const result: {
    users: {
        id: number;
        name: string;
        age: number | null;
    };
    userPets: {
        id: number;
        name: string;
        ownerId: number;
    };
}[];
```
</Section>

### Cross Join
<Section>
```typescript copy
const result = await db.select().from(users).crossJoin(pets)
```
```sql
select ... from `users` cross join `pets`
```
```typescript
// result type
const result: {
    users: {
        id: number;
        name: string;
        age: number | null;
    };
    pets: {
        id: number;
        name: string;
        ownerId: number;
    };
}[];
```
</Section>

### Cross Join Lateral
<Section>
```typescript copy
const subquery = db.select().from(pets).where(gte(users.age, 16)).as('userPets')
const result = await db.select().from(users).crossJoinLateral(subquery)
```
```sql
select ... from `users` cross join lateral (select ... from `pets` where `users`.`age` >= 16) `userPets`
```
```typescript
// result type
const result: {
    users: {
        id: number;
        name: string;
        age: number | null;
    };
    userPets: {
        id: number;
        name: string;
        ownerId: number;
    };
}[];
```
</Section>

## Partial select
If you need to select a particular subset of fields or to have a flat response type, Drizzle ORM
supports joins with partial select and will automatically infer return type based on `.select({ ... })` structure.
<Section>
```typescript copy
await db.select({
  userId: users.id,
  petId: pets.id,
}).from(users).leftJoin(pets, eq(users.id, pets.ownerId))
```
```sql
select `users`.`id`, `pets`.`id` from `users` left join `pets` on `users`.`id` = `pets`.`owner_id`
```
```typescript
// result type
const result: {
  userId: number;
  petId: number | null;
}[];
```
</Section>
You might've noticed that `petId` can be null now, it's because we're left joining and there can be users without a pet.

It's very important to keep in mind when using `sql` operator for partial selection fields and aggregations when needed,
you should to use `sql<type | null>` for proper result type inference, that one is on you!
<Section>
```typescript copy
const result = await db.select({
  userId: users.id,
  petId: pets.id,
  petName1: sql`upper(${pets.name})`,
  petName2: sql<string | null>`upper(${pets.name})`,
  //˄we should explicitly tell 'string | null' in type, since we're left joining that field
}).from(users).leftJoin(pets, eq(users.id, pets.ownerId))
```
```sql
select `users`.`id`, `pets`.`id`, upper(`pets`.`name`), upper(`pets`.`name`) from `users` left join `pets` on `users`.`id` = `pets`.`owner_id`
```
```typescript
// result type
const result: {
  userId: number;
  petId: number | null;
  petName1: unknown;
  petName2: string | null;
}[];
```
</Section>
To avoid plethora of nullable fields when joining tables with lots of columns we can utilise our **nested select object syntax**,
our smart type inference will make whole object nullable instead of making all table fields nullable!
<Section>
```typescript copy
await db.select({
  userId: users.id,
  userName: users.name,
  pet: {
    id: pets.id,
    name: pets.name,
    upperName: sql<string>`upper(${pets.name})`
  }
}).from(users).leftJoin(pets, eq(users.id, pets.ownerId))
```
```sql
select ... from `users` left join `pets` on `users`.`id` = `pets`.`owner_id`
```
```typescript
// result type
const result: {
    userId: number;
    userName: string;
    pet: {
        id: number;
        name: string;
        upperName: string;
    } | null;
}[];
```
</Section>

## Aliases & Selfjoins
Drizzle ORM supports table aliases which comes really handy when you need to do selfjoins.

Lets say you need to fetch users with their parents:
<CodeTabs items={["index.ts", "schema.ts"]}>
<CodeTab>
```typescript copy
import { user } from "./schema";
import { alias } from "drizzle-orm/mysql-core";

const parent = alias(user, "parent");
const result = await db
  .select()
  .from(user)
  .leftJoin(parent, eq(parent.id, user.parentId));
```
```sql
select ... from `user` left join `user` `parent` on `parent`.`id` = `user`.`parent_id`
```
```typescript
// result type
const result: {
    user: {
        id: number;
        name: string;
        parentId: number;
    };
    parent: {
        id: number;
        name: string;
        parentId: number;
    } | null;
}[];
```
</CodeTab>

```typescript
export const user = mysqlTable("user", {
  id: int().primaryKey().autoincrement(),
  name: varchar({ length: 255 }).notNull(),
  parentId: int("parent_id").notNull().references((): AnyMySqlColumn => user.id),
});
```

</CodeTabs>

## Aggregating results
Drizzle ORM delivers name-mapped results from the driver without changing the structure.

You're free to operate with results the way you want, here's an example of mapping many-one relational data:
```typescript
type User = typeof users.$inferSelect;
type Pet = typeof pets.$inferSelect;

const rows = await db
  .select({
    user: users,
    pet: pets,
  })
  .from(users)
  .leftJoin(pets, eq(users.id, pets.ownerId));

const result = rows.reduce<Record<number, { user: User; pets: Pet[] }>>((acc, row) => {
  const user = row.user;
  const pet = row.pet;

  if (typeof acc[user.id] === "undefined") {
    acc[user.id] = { user, pets: [] };
  }

  if (pet) {
    acc[user.id]!.pets.push(pet);
  }

  return acc;
}, {});

// result type
const result: Record<number, {
    user: User;
    pets: Pet[];
}>
```

## Many-to-one example
```typescript
import { mysqlTable, varchar, int } from 'drizzle-orm/mysql-core';
import { drizzle } from 'drizzle-orm/mysql2';

const cities = mysqlTable('cities', {
  id: int().primaryKey().autoincrement(),
  name: varchar({ length: 255 }),
});

const users = mysqlTable('users', {
  id: int().primaryKey().autoincrement(),
  name: varchar({ length: 255 }),
  cityId: int('city_id').references(() => cities.id)
});

const db = drizzle();

const result = await db.select().from(cities).leftJoin(users, eq(cities.id, users.cityId));
```
## Many-to-many example
```typescript
const users = mysqlTable('users', {
  id: int().primaryKey().autoincrement(),
  name: varchar({ length: 255 }),
});

const chatGroups = mysqlTable('chat_groups', {
  id: int().primaryKey().autoincrement(),
  name: varchar({ length: 255 }),
});

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


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


Source: https://orm.drizzle.team/docs/mysql/kit-custom-migrations

import CodeTab from '@mdx/CodeTab.astro';
import CodeTabs from '@mdx/CodeTabs.astro';
import Section from '@mdx/Section.astro';
import Tab from '@mdx/Tab.astro';
import Tabs from '@mdx/Tabs.astro';
import Callout from '@mdx/Callout.astro';
import Npm from '@mdx/Npm.astro';
import Npx from '@mdx/Npx.astro';
import Steps from '@mdx/Steps.astro';
import Prerequisites from "@mdx/Prerequisites.astro"

# Migrations with Drizzle Kit
<Prerequisites>
- Get started with Drizzle and `drizzle-kit` - [read here](/docs/mysql/get-started)
- Drizzle schema fundamentals - [read here](/docs/mysql/sql-schema-declaration)
- Database connection basics - [read here](/docs/mysql/connect-overview)
- Drizzle migrations fundamentals - [read here](/docs/mysql/migrations)
- Drizzle Kit [overview](/docs/mysql/kit-overview) and [config file](/docs/mysql/drizzle-config-file)
- `drizzle-kit generate` command - [read here](/docs/mysql/drizzle-kit-generate)
- `drizzle-kit migrate` command - [read here](/docs/mysql/drizzle-kit-migrate)
</Prerequisites>

Drizzle lets you generate empty migration files to write your own custom SQL migrations 
for DDL alternations currently not supported by Drizzle Kit or data seeding, which you can then run with [`drizzle-kit migrate`](/docs/mysql/drizzle-kit-migrate) command.

```shell
drizzle-kit generate --custom --name=seed-users
```
<Section>
```plaintext {4}
📦 <project root>
 ├ 📂 drizzle
 │ ├ 📂 20242409125510_init_sql
 │ └ 📂 20242409135510_seed-users
 ├ 📂 src
 └ …
```
```sql
-- ./drizzle/20242409135510_seed-users.sql

INSERT INTO "users" ("name") VALUES('Dan');
INSERT INTO "users" ("name") VALUES('Andrew');
INSERT INTO "users" ("name") VALUES('Dandrew');
```
</Section>

### Running JavaScript and TypeScript migrations
We will add ability to run custom JavaScript and TypeScript migration/seeding scripts in the upcoming release, you can follow [github discussion](https://github.com/drizzle-team/drizzle-orm/discussions/2832).

Source: https://orm.drizzle.team/docs/mysql/kit-overview

import CodeTab from '@mdx/CodeTab.astro';
import CodeTabs from '@mdx/CodeTabs.astro';
import Section from '@mdx/Section.astro';
import Tab from '@mdx/Tab.astro';
import Tabs from '@mdx/Tabs.astro';
import Callout from '@mdx/Callout.astro';
import Npm from '@mdx/Npm.astro';
import Npx from '@mdx/Npx.astro';
import Steps from '@mdx/Steps.astro';
import Prerequisites from "@mdx/Prerequisites.astro"

# Migrations with Drizzle Kit
<Prerequisites>
- Get started with Drizzle and `drizzle-kit` - [read here](/docs/mysql/get-started)
- Drizzle schema fundamentals - [read here](/docs/mysql/sql-schema-declaration)
- Database connection basics - [read here](/docs/mysql/connect-overview)
- Drizzle migrations fundamentals - [read here](/docs/mysql/migrations)
</Prerequisites>


**Drizzle Kit** is a CLI tool for managing SQL database migrations with Drizzle.
<Npm>
  -D drizzle-kit
</Npm>
<Callout type="warning">
Make sure to first go through Drizzle [get started](/docs/mysql/get-started) and [migration fundamentals](/docs/mysql/migrations) and pick SQL migration flow that suits your business needs best. 
</Callout>

Based on your schema, Drizzle Kit let's you generate and run SQL migration files, 
push schema directly to the database, pull schema from database, spin up drizzle studio and has a couple of utility commands.
<Npx>
drizzle-kit generate
drizzle-kit migrate
drizzle-kit push
drizzle-kit pull
drizzle-kit check
drizzle-kit up
drizzle-kit studio
drizzle-kit export
</Npx>


|                                                      |                                                                                                                                                                    |
| :--------------------------------------------------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| [`drizzle-kit generate`](/docs/mysql/drizzle-kit-generate) | lets you generate SQL migration files based on your Drizzle schema either upon declaration or on subsequent changes, [see here](/docs/mysql/drizzle-kit-generate).       |
| [`drizzle-kit migrate`](/docs/mysql/drizzle-kit-migrate)   | lets you apply generated SQL migration files to your database, [see here](/docs/mysql/drizzle-kit-migrate).                                                              |
| [`drizzle-kit pull`](/docs/mysql/drizzle-kit-pull)         | lets you pull(introspect) database schema, convert it to Drizzle schema and save it to your codebase, [see here](/docs/mysql/drizzle-kit-pull)                           |
| [`drizzle-kit push`](/docs/mysql/drizzle-kit-push)         | lets you push your Drizzle schema to database either upon declaration or on subsequent schema changes, [see here](/docs/mysql/drizzle-kit-push)                          |
| [`drizzle-kit studio`](/docs/mysql/drizzle-kit-studio)     | will connect to your database and spin up proxy server for Drizzle Studio which you can use for convenient database browsing, [see here](/docs/mysql/drizzle-kit-studio) |
| [`drizzle-kit check`](/docs/mysql/drizzle-kit-check)       | will walk through all generate migrations and check for any race conditions(collisions) of generated migrations, [see here](/docs/mysql/drizzle-kit-check)               |
| [`drizzle-kit up`](/docs/mysql/drizzle-kit-up)             | used to upgrade snapshots of previously generated migrations, [see here](/docs/mysql/drizzle-kit-up)                                                                     |
| [`drizzle-kit export`](/docs/mysql/drizzle-kit-export)     | used converting TS schema into raw SQL DDL and print it out [see here](/docs/mysql/drizzle-kit-export)                                                                     |
<br/>

Drizzle Kit is configured through [drizzle.config.ts](/docs/mysql/drizzle-config-file) configuration file or via CLI params.<br/>
It's required to at least provide SQL `dialect` and `schema` path for Drizzle Kit to know how to generate migrations.
```
📦 <project root>
 ├ 📂 drizzle
 ├ 📂 src
 ├ 📜 .env
 ├ 📜 drizzle.config.ts  <--- Drizzle config file
 ├ 📜 package.json
 └ 📜 tsconfig.json
```

<CodeTabs items={["simple config", "extended config"]}>
```ts
import { defineConfig } from "drizzle-kit";

export default defineConfig({
  dialect: "mysql",
  schema: "./src/schema.ts",
});
```
```ts
import { defineConfig } from "drizzle-kit";

export default defineConfig({
  out: "./drizzle",
  dialect: "mysql",
  schema: "./src/schema.ts",

  dbCredentials: {
    url: "./database/",
  },

  tablesFilter: "*",

  introspect: {
    casing: "camel",
  },

  migrations: {
    table: "__drizzle_migrations__",
  },

  breakpoints: true,
  verbose: true,
});
```
</CodeTabs>

You can provide Drizzle Kit config path via CLI param, it's very useful when you have multiple database stages or multiple databases or different databases on the same project:

<Npx>
  drizzle-kit push --config=drizzle-dev.drizzle.config
  drizzle-kit push --config=drizzle-prod.drizzle.config
</Npx>
```plaintext {5-6}
📦 <project root>
 ├ 📂 drizzle
 ├ 📂 src
 ├ 📜 .env
 ├ 📜 drizzle-dev.config.ts
 ├ 📜 drizzle-prod.config.ts
 ├ 📜 package.json
 └ 📜 tsconfig.json
```


Source: https://orm.drizzle.team/docs/mysql/migrations

import Callout from '@mdx/Callout.astro';
import Steps from '@mdx/Steps.astro';
import CodeTab from '@mdx/CodeTab.astro';
import CodeTabs from '@mdx/CodeTabs.astro';
import Section from '@mdx/Section.astro';
import Tab from '@mdx/Tab.astro';
import Tabs from '@mdx/Tabs.astro';
import Npm from '@mdx/Npm.astro';
import Tag from '@mdx/Tag.astro'


# Drizzle migrations fundamentals

SQL databases require you to specify a **strict schema** of entities you're going to store upfront 
and if (when) you need to change the shape of those entities - you will need to do it via **schema migrations**.

There're multiple production grade ways of managing database migrations. 
Drizzle is designed to perfectly suits all of them, regardless of you going **database first** or **codebase first**.

**Database first** is when your database schema is a source of truth. You manage your database schema either directly on the database or 
via database migration tools and then you pull your database schema to your codebase application level entities.  
 
**Codebase first** is when database schema in your codebase is a source of truth and is under version control. You declare and manage your database schema in JavaScript/TypeScript
and then you apply that schema to the database itself either with Drizzle, directly or via external migration tools. 

#### How can Drizzle help?
We've built [**drizzle-kit**](/docs/mysql/kit-overview) - CLI app for managing migrations with Drizzle. 
```shell
drizzle-kit migrate
drizzle-kit generate
drizzle-kit push
drizzle-kit pull
drizzle-kit export
```
It is designed to let you choose how to approach migrations based on your current business demands. 

It fits in both database and codebase first approaches, it lets you **push your schema** or **generate SQL migration** files or **pull the schema** from database. 
It is perfect wether you work alone or in a team.
<br/>

<hr/>
<rem/>

**Now let's pick the best option for your project:**
<rem/>

<Tag style="font-size: 12px">**Option 1**</Tag>
> I manage database schema myself using external migration tools or by running SQL migrations directly on my database.
> From Drizzle I just need to get current state of the schema from my database and save it as TypeScript schema file.

<Callout collapsed="Expand details">
That's a **database first** approach. You have your database schema as a **source of truth** and 
Drizzle lets you pull database schema to TypeScript using [`drizzle-kit pull`](/docs/mysql/drizzle-kit-pull) command.

<Section>
```
                                  ┌────────────────────────┐      ┌─────────────────────────────────────┐ 
                                  │                        │ <---  CREATE TABLE `users` (
┌──────────────────────────┐      │                        │       	`id` int AUTO_INCREMENT PRIMARY KEY,
│ ~ drizzle-kit pull       │      │                        │       	`name` text,
└─┬────────────────────────┘      │        DATABASE        │       	`age` int,
  │                               │                        │       	CONSTRAINT ... UNIQUE INDEX(`age`)
  └ Pull datatabase schema -----> │                        │       );
  ┌ Generate Drizzle       <----- │                        │
  │ schema TypeScript file        └────────────────────────┘
  │
  v
```
```typescript
import * as m from "drizzle-orm/mysql-core";

export const users = m.mysqlTable("users", {
    id: m.int().primaryKey().autoincrement(),
    name: m.text(),
    age: m.int(),
  },
  (table) => [m.uniqueIndex("users_age_unique_idx").on(table.age)]
);
```
</Section>
</Callout>

<rem/>
<rem/>
<rem/>

<Tag style="font-size: 12px">**Option 2**</Tag>
> I want to have database schema in my TypeScript codebase, 
> I don't wanna deal with SQL migration files.  
> I want Drizzle to "push" my schema directly to the database

<Callout collapsed="Expand details">
That's a **codebase first** approach. You have your TypeScript Drizzle schema as a **source of truth** and 
Drizzle lets you push schema changes to the database using [`drizzle-kit push`](/docs/mysql/drizzle-kit-push) command.

That's the best approach for rapid prototyping and we've seen dozens of teams 
and solo developers successfully using it as a primary migrations flow in their production applications.

<Section>
```typescript {6} filename="src/schema.ts"
import * as p from "drizzle-orm/mysql-core";

export const users = p.mysqlTable("users", {
  id: p.int().primaryKey().autoincrement(),
  name: p.varchar({ length: 255 }),
  email: p.varchar({ length: 255 }).notNull(), // <--- added column
});
```
```
Add column to `users` table                                                                          
┌─────────────────────────────────────────────┐                  
│ + email: varchar({ length: 255 }).notNull() │                  
└─┬───────────────────────────────────────────┘                  
  │                                           
  v                                           
┌──────────────────────────┐                  
│ ~ drizzle-kit push       │                  
└─┬────────────────────────┘                  
  │                                           ┌──────────────────────────┐
  └ Pull current datatabase schema ---------> │                          │
                                              │                          │
  ┌ Generate alternations based on diff <---- │         DATABASE         │
  │                                           │                          │
  └ Apply migrations to the database -------> │                          │
                                       │      └──────────────────────────┘
                                       │
  ┌────────────────────────────────────┴─────────────────┐
   ALTER TABLE `users` ADD `email` varchar(255) NOT NULL; 
```
</Section>
</Callout>

<rem/>
<rem/>
<rem/>

<Tag style="font-size: 12px">**Option 3**</Tag>
> I want to have database schema in my TypeScript codebase, 
> I want Drizzle to generate SQL migration files for me and apply them to my database

<Callout collapsed="Expand details">
That's a **codebase first** approach. You have your TypeScript Drizzle schema as a source of truth and 
Drizzle lets you generate SQL migration files based on your schema changes with [`drizzle-kit generate`](/docs/mysql/drizzle-kit-generate)
and then apply them to the database with [`drizzle-kit migrate`](/docs/mysql/drizzle-kit-migrate) commands. 
<Section>
```typescript filename="src/schema.ts"
import * as p from "drizzle-orm/mysql-core";

export const users = p.mysqlTable("users", {
  id: p.int().primaryKey().autoincrement(),
  name: p.varchar({ length: 255 }),
  email: p.varchar({ length: 255 }).unique(),
});
```
```                                  
┌────────────────────────┐                  
│ $ drizzle-kit generate │                  
└─┬──────────────────────┘                  
  │                                           
  └ 1. read previous migration folders
    2. find diff between current and previous schema
    3. prompt developer for renames if necessary
  ┌ 4. generate SQL migration and persist to file
  │    ┌─┴───────────────────────────────────────┐  
  │      📂 drizzle       
  │      └ 📂 20242409125510_premium_mister_fear
  │        ├ 📜 snapshot.json
  │        └ 📜 migration.sql
  v
```
```sql
-- drizzle/20242409125510_premium_mister_fear/migration.sql

CREATE TABLE `users` (
	`id` int AUTO_INCREMENT PRIMARY KEY,
	`name` varchar(255),
	`email` varchar(255),
	CONSTRAINT `email_unique` UNIQUE INDEX(`email`)
);
```
```
┌───────────────────────┐                  
│ $ drizzle-kit migrate │                  
└─┬─────────────────────┘                  
  │                                                         ┌──────────────────────────┐                                         
  └ 1. read migration.sql files in migrations folder        │                          │
    2. fetch migration history from database -------------> │                          │
  ┌ 3. pick previously unapplied migrations <-------------- │         DATABASE         │
  └ 4. apply new migration to the database ---------------> │                          │
                                                            │                          │
                                                            └──────────────────────────┘
[✓] done!                                                 
```
</Section>
</Callout>

<rem/>
<rem/>
<rem/>

<Tag style="font-size: 12px">**Option 4**</Tag>
> I want to have database schema in my TypeScript codebase,
> I want Drizzle to generate SQL migration files for me and I want Drizzle to apply them during runtime

<Callout collapsed="Expand details">
That's a **codebase first** approach. You have your TypeScript Drizzle schema as a source of truth and 
Drizzle lets you generate SQL migration files based on your schema changes with [`drizzle-kit generate`](/docs/mysql/drizzle-kit-generate) and then 
you can apply them to the database during runtime of your application.

This approach is widely used for **monolithic** applications when you apply database migrations 
during zero downtime deployment and rollback DDL changes if something fails. 
This is also used in **serverless** deployments with migrations running in **custom resource** once during deployment process.

<Section>
```typescript filename="src/schema.ts"
import * as p from "drizzle-orm/mysql-core";

export const users = p.mysqlTable("users", {
  id: p.int().primaryKey().autoincrement(),
  name: p.varchar({ length: 255 }),
  email: p.varchar({ length: 255 }).unique(),
});
```
```                                  
┌────────────────────────┐                  
│ $ drizzle-kit generate │                  
└─┬──────────────────────┘                  
  │                                           
  └ 1. read previous migration folders
    2. find diff between current and previous schema
    3. prompt developer for renames if necessary
  ┌ 4. generate SQL migration and persist to file
  │    ┌─┴───────────────────────────────────────┐  
  │      📂 drizzle       
  │      └ 📂 20242409125510_premium_mister_fear
  │        ├ 📜 snapshot.json
  │        └ 📜 migration.sql
  v
```
```sql
-- drizzle/20242409125510_premium_mister_fear/migration.sql

CREATE TABLE `users` (
	`id` int AUTO_INCREMENT PRIMARY KEY,
	`name` varchar(255),
	`email` varchar(255),
	CONSTRAINT `email_unique` UNIQUE INDEX(`email`)
);
```
```ts
// index.ts
import { drizzle } from "drizzle-orm/mysql2"
import { migrate } from 'drizzle-orm/mysql2/migrator';

const db = drizzle(process.env.DATABASE_URL);

await migrate(db);
```
```
┌───────────────────────┐                  
│ npx tsx src/index.ts  │                  
└─┬─────────────────────┘                  
  │                                                      
  ├ 1. init database connection                             ┌──────────────────────────┐                                         
  └ 2. read migration.sql files in migrations folder        │                          │
    3. fetch migration history from database -------------> │                          │
  ┌ 4. pick previously unapplied migrations <-------------- │         DATABASE         │
  └ 5. apply new migration to the database ---------------> │                          │
                                                            │                          │
                                                            └──────────────────────────┘
[✓] done!                                                 
```
</Section>
</Callout>

<rem/>
<rem/>
<rem/>

<Tag style="font-size: 12px">**Option 5**</Tag>
> I want to have database schema in my TypeScript codebase,
> I want Drizzle to generate SQL migration files for me,
> but I will apply them to my database myself or via external migration tools 

<Callout collapsed="Expand details">
That's a **codebase first** approach. You have your TypeScript Drizzle schema as a source of truth and 
Drizzle lets you generate SQL migration files based on your schema changes with [`drizzle-kit generate`](/docs/mysql/drizzle-kit-generate) and then 
you can apply them to the database either directly or via external migration tools.

<Section>
```typescript filename="src/schema.ts"
import * as p from "drizzle-orm/mysql-core";

export const users = p.mysqlTable("users", {
  id: p.int().primaryKey().autoincrement(),
  name: p.varchar({ length: 255 }),
  email: p.varchar({ length: 255 }).unique(),
});
```
```                                  
┌────────────────────────┐                  
│ $ drizzle-kit generate │                  
└─┬──────────────────────┘                  
  │                                           
  └ 1. read previous migration folders
    2. find diff between current and previous scheama
    3. prompt developer for renames if necessary
  ┌ 4. generate SQL migration and persist to file
  │    ┌─┴───────────────────────────────────────┐  
  │      📂 drizzle       
  │      └ 📂 20242409125510_premium_mister_fear
  │        ├ 📜 snapshot.json
  │        └ 📜 migration.sql
  v
```
```sql
-- drizzle/20242409125510_premium_mister_fear/migration.sql

CREATE TABLE `users` (
  	`id` int AUTO_INCREMENT PRIMARY KEY,
  `name` varchar(255),
  `email` varchar(255),
  CONSTRAINT `email_unique` UNIQUE INDEX(`email`)
);
```
```
┌───────────────────────────────────┐                  
│ (._.) now you run your migrations │           
└─┬─────────────────────────────────┘  
  │
 directly to the database
  │                                         ┌────────────────────┐
  ├────────────────────────────────────┬───>│                    │  
  │                                    │    │      Database      │           
 or via external tools                 │    │                    │   
  │                                    │    └────────────────────┘
  │  ┌────────────────────┐            │      
  └──│ Bytebase           ├────────────┘         
     ├────────────────────┤  
     │ Liquibase          │
     ├────────────────────┤ 
     │ Atlas              │
     ├────────────────────┤ 
     │ etc…               │
     └────────────────────┘

[✓] done!                                                 
```
</Section>
</Callout>

<rem/>
<rem/>
<rem/>

<Tag style="font-size: 12px">**Option 6**</Tag>
> I want to have database schema in my TypeScript codebase,
> I want Drizzle to output the SQL representation of my Drizzle schema to the console,
> and I will apply them to my database via [Atlas](https://atlasgo.io/guides/orms/drizzle)

<Callout collapsed="Expand details">
That's a **codebase first** approach. You have your TypeScript Drizzle schema as a source of truth and 
Drizzle lets you export SQL statements based on your schema changes with [`drizzle-kit export`](/docs/mysql/drizzle-kit-generate) and then 
you can apply them to the database via [Atlas](https://atlasgo.io/guides/orms/drizzle) or other external SQL migration tools.

<Section>
```typescript filename="src/schema.ts"
import * as p from 'drizzle-orm/mysql-core';

export const users = p.mysqlTable('users', {
  id: p.int().primaryKey().autoincrement(),
  name: p.varchar({ length: 255 }),
  email: p.varchar({ length: 255 }).unique(),
});
```
```                                  
┌────────────────────────┐                  
│ $ drizzle-kit export   │                  
└─┬──────────────────────┘                  
  │                                           
  └ 1. read your drizzle schema
    2. generated SQL representation of your schema
  ┌ 3. outputs to console
  │    
  │        
  v
```
```sql
CREATE TABLE `users` (
        `id` int AUTO_INCREMENT PRIMARY KEY,
        `name` varchar(255),
        `email` varchar(255),
        CONSTRAINT `email_unique` UNIQUE INDEX(`email`)
);
```
```
┌───────────────────────────────────┐                  
│ (._.) now you run your migrations │           
└─┬─────────────────────────────────┘  
  │
 via Atlas
  │                                    ┌──────────────┐
  │  ┌────────────────────┐            │              │
  └──│ Atlas              ├───────────>│  Database    │      
     └────────────────────┘            │              │       
                                       └──────────────┘

[✓] done!                                                 
```
</Section>
</Callout>

<rem/>
<rem/>


Source: https://orm.drizzle.team/docs/mysql/operators

import Section from '@mdx/Section.astro';

# Filter and conditional operators
We natively support all dialect specific filter and conditional operators.

You can import all filter & conditional from `drizzle-orm`:
```typescript copy
import { eq, ne, gt, gte, ... } from "drizzle-orm";
```

### eq


Value equal to `n`
<Section>
```typescript copy
import { eq } from "drizzle-orm";

db.select().from(table).where(eq(table.column, 5));
```

```sql copy
SELECT * FROM `table` WHERE `table`.`column` = 5
```
</Section>

<Section>
```typescript
import { eq } from "drizzle-orm";

db.select().from(table).where(eq(table.column1, table.column2));
```

```sql
SELECT * FROM `table` WHERE `table`.`column1` = `table`.`column2`
```
</Section>

### ne

  
Value is not equal to `n`  
<Section>
```typescript
import { ne } from "drizzle-orm";

db.select().from(table).where(ne(table.column, 5));
```

```sql
SELECT * FROM `table` WHERE `table`.`column` <> 5
```
</Section>

<Section>
```typescript
import { ne } from "drizzle-orm";

db.select().from(table).where(ne(table.column1, table.column2));
```

```sql
SELECT * FROM `table` WHERE `table`.`column1` <> `table`.`column2`
```
</Section>

## ---

### gt
 
  
Value is greater than `n`
<Section>
```typescript
import { gt } from "drizzle-orm";

db.select().from(table).where(gt(table.column, 5));
```

```sql
SELECT * FROM `table` WHERE `table`.`column` > 5
```
</Section>

<Section>
```typescript
import { gt } from "drizzle-orm";

db.select().from(table).where(gt(table.column1, table.column2));
```

```sql
SELECT * FROM `table` WHERE `table`.`column1` > `table`.`column2`
```
</Section>

### gte

  
Value is greater than or equal to `n`
<Section>
```typescript
import { gte } from "drizzle-orm";

db.select().from(table).where(gte(table.column, 5));
```

```sql
SELECT * FROM `table` WHERE `table`.`column` >= 5
```
</Section>

<Section>
```typescript
import { gte } from "drizzle-orm";

db.select().from(table).where(gte(table.column1, table.column2));
```

```sql
SELECT * FROM `table` WHERE `table`.`column1` >= `table`.`column2`
```
</Section>

### lt

  
Value is less than `n`
<Section>
```typescript
import { lt } from "drizzle-orm";

db.select().from(table).where(lt(table.column, 5));
```

```sql
SELECT * FROM `table` WHERE `table`.`column` < 5
```
</Section>

<Section>
```typescript
import { lt } from "drizzle-orm";

db.select().from(table).where(lt(table.column1, table.column2));
```

```sql
SELECT * FROM `table` WHERE `table`.`column1` < `table`.`column2`
```
</Section>

### lte

  
Value is less than or equal to `n`.

<Section>
```typescript
import { lte } from "drizzle-orm";

db.select().from(table).where(lte(table.column, 5));
```

```sql
SELECT * FROM `table` WHERE `table`.`column` <= 5
```
</Section>

<Section>
```typescript
import { lte } from "drizzle-orm";

db.select().from(table).where(lte(table.column1, table.column2));
```

```sql
SELECT * FROM `table` WHERE `table`.`column1` <= `table`.`column2`
```
</Section>

## ---

### exists

  
Value exists
<Section>
```typescript
import { exists } from "drizzle-orm";

const query = db.select().from(table2)
db.select().from(table).where(exists(query));
```

```sql
SELECT * FROM `table` WHERE EXISTS (SELECT * FROM `table2`)
```
</Section>

### notExists

<Section>
```typescript
import { notExists } from "drizzle-orm";

const query = db.select().from(table2)
db.select().from(table).where(notExists(query));
```

```sql
SELECT * FROM `table` WHERE NOT EXISTS (SELECT * FROM `table2`)
```
</Section>

### isNull

  
Value is `null`
<Section>
```typescript
import { isNull } from "drizzle-orm";

db.select().from(table).where(isNull(table.column));
```

```sql
SELECT * FROM `table` WHERE `table`.`column` IS NULL
```
</Section>

### isNotNull

  
Value is not `null`
<Section>
```typescript
import { isNotNull } from "drizzle-orm";

db.select().from(table).where(isNotNull(table.column));
```

```sql
SELECT * FROM `table` WHERE `table`.`column` IS NOT NULL
```
</Section>

## ---

### inArray

  
Value is in array of values
<Section>
```typescript
import { inArray } from "drizzle-orm";

db.select().from(table).where(inArray(table.column, [1, 2, 3, 4]));
```

```sql
SELECT * FROM `table` WHERE `table`.`column` IN (1, 2, 3, 4)
```
</Section>

<Section>
```typescript
import { inArray } from "drizzle-orm";

const query = db.select({ data: table2.column }).from(table2);
db.select().from(table).where(inArray(table.column, query));
```

```sql
SELECT * FROM `table` WHERE `table`.`column` IN (SELECT `table2`.`column` FROM `table2`)
```
</Section>

### notInArray

  
Value is not in array of values
<Section>
```typescript
import { notInArray } from "drizzle-orm";

db.select().from(table).where(notInArray(table.column, [1, 2, 3, 4]));
```

```sql
SELECT * FROM `table` WHERE `table`.`column` NOT IN (1, 2, 3, 4)
```
</Section>

<Section>
```typescript
import { notInArray } from "drizzle-orm";

const query = db.select({ data: table2.column }).from(table2);
db.select().from(table).where(notInArray(table.column, query));
```

```sql
SELECT * FROM `table` WHERE `table`.`column` NOT IN (SELECT `table2`.`column` FROM `table2`)
```
</Section>

## ---

### between

  
Value is between two values
<Section>
```typescript
import { between } from "drizzle-orm";

db.select().from(table).where(between(table.column, 2, 7));
```

```sql
SELECT * FROM `table` WHERE `table`.`column` BETWEEN 2 AND 7
```
</Section>

### notBetween

  
Value is not between two value
<Section>
```typescript
import { notBetween } from "drizzle-orm";

db.select().from(table).where(notBetween(table.column, 2, 7));
```

```sql
SELECT * FROM `table` WHERE `table`.`column` NOT BETWEEN 2 AND 7
```
</Section>

## ---

### like

  
Value is like other value, case sensitive
<Section>
```typescript
import { like } from "drizzle-orm";

db.select().from(table).where(like(table.column, "%llo wor%"));
```

```sql
SELECT * FROM `table` WHERE `table`.`column` LIKE '%llo wor%'
```
</Section>

### notLike

  
Value is not like some other value, case insensitive
<Section>
```typescript
import { notLike } from "drizzle-orm";

db.select().from(table).where(notLike(table.column, "%llo wor%"));
```

```sql
SELECT * FROM `table` WHERE `table`.`column` NOT LIKE '%llo wor%'
```
</Section>

## ---

### not
  
All conditions must return `false`.

<Section>
```typescript
import { eq, not } from "drizzle-orm";

db.select().from(table).where(not(eq(table.column, 5)));
```

```sql
SELECT * FROM `table` WHERE NOT (`table`.`column` = 5)
```
</Section>

### and

  
All conditions must return `true`.

<Section>
```typescript
import { gt, lt, and } from "drizzle-orm";

db.select().from(table).where(and(gt(table.column, 5), lt(table.column, 7)));
```

```sql
SELECT * FROM `table` WHERE (`table`.`column` > 5 AND `table`.`column` < 7)
```
</Section>

### or

  
One or more conditions must return `true`.

<Section>
```typescript
import { gt, lt, or } from "drizzle-orm";

db.select().from(table).where(or(gt(table.column, 5), lt(table.column, 7)));
```

```sql
SELECT * FROM `table` WHERE (`table`.`column` > 5 OR `table`.`column` < 7)
```
</Section>

## ---


Source: https://orm.drizzle.team/docs/mysql/overview

import Callout from '@mdx/Callout.astro';
import CodeTabs from '@mdx/CodeTabs.astro';
import YoutubeCards from '@mdx/YoutubeCards.astro';
import GetStartedLinks from '@mdx/GetStartedLinks/index.astro'

# Drizzle ORM

Drizzle ORM is a headless TypeScript ORM with a head. 🐲
> Drizzle is a good friend who's there for you when necessary and doesn't bother when you need some space.

It looks and feels simple, performs on day _1000_ of your project,\
lets you do things your way, and is there when you need it.

**It's the only ORM with both [relational](/docs/mysql/rqb) and [SQL-like](/docs/mysql/select) query APIs**, 
providing you the best of both worlds when it comes to accessing your relational data. 
Drizzle is lightweight, performant, typesafe, non-lactose, gluten-free, sober, flexible and **serverless-ready by design**.
Drizzle is not just a library, it's an experience. 🤩

[![Drizzle bestofjs](@/assets/images/bestofjs.jpg)](https://bestofjs.org/projects/drizzle-orm)

## Headless ORM? 
First and foremost, Drizzle is a library and a collection of complementary opt-in tools. 

**ORM** stands for _object relational mapping_, and developers tend to call Django-like or Spring-like tools an ORM. 
We truly believe it's a misconception based on legacy nomenclature, and we call them **data frameworks**.

<Callout type="error" emoji="️💔">
  With data frameworks you have to build projects **around them** and not **with them**.
</Callout>

**Drizzle** lets you build your project the way you want, without interfering with your project or structure. 

Using Drizzle you can define and manage database schemas in TypeScript, access your data in a SQL-like 
or relational way, and take advantage of opt-in tools 
to push your developer experience _through the roof_. 🤯 

## Why SQL-like?
**If you know SQL, you know Drizzle.**

Other ORMs and data frameworks tend to deviate/abstract you away from SQL, which 
leads to a double learning curve: needing to know both SQL and the framework's API.  

Drizzle is the opposite. 
We embrace SQL and built Drizzle to be SQL-like at its core, so you can have zero to no 
learning curve and access to the full power of SQL.  

We bring all the familiar **[SQL schema](/docs/mysql/sql-schema-declaration)**, **[queries](/docs/mysql/select)**, 
**[automatic migrations](/docs/mysql/migrations)** and **[one more thing](/docs/mysql/rqb)**. ✨

<CodeTabs items={["index.ts", "schema.ts", "migration.sql"]}>
```typescript copy
// Access your data
await db
	.select()
	.from(countries)
	.leftJoin(cities, eq(cities.countryId, countries.id))
	.where(eq(countries.id, 10))
```
```typescript copy
// manage your schema
export const countries = mysqlTable('countries', {
  id: int().primaryKey().autoincrement(),
  name: varchar({ length: 256 }),
});

export const cities = mysqlTable('cities', {
  id: int().primaryKey().autoincrement(),
  name: varchar({ length: 256 }),
  countryId: int('country_id').references(() => countries.id),
});
```
```sql
CREATE TABLE `countries` (
	`id` int AUTO_INCREMENT PRIMARY KEY,
	`name` varchar(256)
);

CREATE TABLE `cities` (
	`id` int AUTO_INCREMENT PRIMARY KEY,
	`name` varchar(256),
	`country_id` int
);

ALTER TABLE `cities` ADD CONSTRAINT `cities_country_id_countries_id_fkey` FOREIGN KEY (`country_id`) REFERENCES `countries`(`id`);
```
</CodeTabs>

## Why not SQL-like?
We're always striving for a perfectly balanced solution, and while SQL-like does cover 100% of the needs, 
there are certain common scenarios where you can query data in a better way.  

We've built the **[Queries API](/docs/mysql/rqb)** for you, so you can fetch relational nested data from the database 
in the most convenient and performant way, and never think about joins and data mapping.  

**Drizzle always outputs exactly 1 SQL query.** Feel free to use it with serverless databases and never worry about performance or roundtrip costs!

```ts
const result = await db.query.users.findMany({
	with: {
		posts: true
	},
});
```

## Serverless?
<Callout type="info" emoji="🥳">
  The best part is no part. **Drizzle has exactly 0 dependencies!**
</Callout>


![Drizzle is slim an Serverless ready](@/assets/images/drizzle31kb.jpg)
  
Drizzle ORM is dialect-specific, slim, performant and serverless-ready **by design**.  

We've spent a lot of time to make sure you have best-in-class SQL dialect support, including Postgres, MySQL, and others.

Drizzle operates natively through industry-standard database drivers. We support all major **[PostgreSQL](/docs/get-started-postgresql)**, **[MySQL](/docs/mysql/get-started-mysql)**, **[SQLite](/docs/sqlite/get-started-sqlite)**, **[SingleStore](/docs/singlestore/get-started-singlestore)**, **[MSSQL](/docs/mssql/get-started-mssql)** or **[CockroachDB](/docs/cockroach/get-started-cockroach)** drivers out there, and we're adding new ones **[really fast](https://twitter.com/DrizzleORM/status/1653082492742647811?s=20)**.  


## Welcome on board!
More and more companies are adopting Drizzle in production, experiencing immense benefits in both DX and performance.

**We're always there to help, so don't hesitate to reach out. We'll gladly assist you in your Drizzle journey!**

We have an outstanding **[Discord community](https://driz.link/discord)** and welcome all builders to our **[Twitter](https://twitter.com/drizzleorm)**.
  
Now go build something awesome with Drizzle and your **[PostgreSQL](/docs/get-started-postgresql)**, **[MySQL](/docs/mysql/get-started-mysql)**, **[SQLite](/docs/sqlite/get-started-sqlite)**, **[MSSQL](/docs/mssql/get-started-mssql)** or **[CockroachDB](/docs/cockroach/get-started-cockroach)** database. 🚀

### Video Showcase

{/* tRPC + NextJS App Router = Simple Typesafe APIs
Jack Herrington 19:17
https://www.youtube.com/watch?v=qCLV0Iaq9zU */}
{/* https://www.youtube.com/watch?v=qDunJ0wVIec */}
{/* https://www.youtube.com/watch?v=NZpPMlSAez0 */}

 {/* https://www.youtube.com/watch?v=-A0kMiJqQRY */}

<YoutubeCards cards={[
	{
		id: "vyU5mJGCJMw",
		title: "Full Drizzle Course for Beginners",
		description: "Code Genix",
		time: "1:37:39",
	},
	{
		id: "7-NZ0MlPpJA",
		title: "Learn Drizzle In 60 Minutes",
		description: "Web Dev Simplified",
		time: "56:09"
	},
	{
		id: "i_mAHOhpBSA",
		title: "Drizzle ORM in 100 Seconds",
		description: "Fireship",
		time: "2:55"
	},
	{
		id: "hIYNOiZXQ7Y",
		title: "Learn Drizzle ORM in 13 mins (crash course)",
		description: "Neon",
		time: "14:00"
	},
	{
		id: "4ZhtoOFKFP8",
		title: "Easiest Database Setup in Next.js&nbsp;14 with Turso&nbsp;&&nbsp;Drizzle",
		description: "Sam Meech-Ward",
		time: '38:08'
	}, 
	{
		id: "NfVELsEZFsA",
		title: "Next.js Project with Vercel, Neon, Drizzle, TailwindCSS, FlowBite and more!",
		description: "CodingEntrepreneurs",
		time: '5:46:28'
	}, 
	{
		id: "_SLxGYzv6jo",
		title: "I Have A New Favorite Database&nbsp;Tool",
		description: "Theo - t3.gg",
		time: '5:46'
	}, 
	{
		id: "Qo-RXkSwOtc",
		title: "Drizzle ORM First impressions - migrations, relations, queries!",
		description: "Marius Espejo",
		time: '33:52'
	},
	{
		id: "yXNEqyvA0OY",
		title: "I want to learn Drizzle ORM, so I'm starting another next14 project",
		description: "Web Dev Cody",
		time: "9:00"
	},
	{
		id: "h7vVhR-dFYo",
		title: "Picking an ORM is Getting Harder...",
		description: "Ben Davis",
		time: "5:18"
	},
	{
		id: "8met6WTk0mQ",
		title: "This New Database Tool is a Game-Changer",
		description: "Josh tried coding",
		time: "8:49"
	},
	{
		id: "woWW1T9DXEY",
		title: "My Favorite Database Tool Just Got EVEN Better",
		description: "Josh tried coding",
		time: "4:23"
	},
	{
		id: "A3l6YYkXzzg",
		title: "SaaS Notion Clone with Realtime cursors, Nextjs 13, Stripe, Drizzle ORM, Tailwind, Supabase, Sockets",
		description: "Web Prodigies",
		time: "11:41:46"
	},
	{
		id: "EQfaw5bDE1s",
		title: "SvelteKit + Drizzle Code Breakdown",
		description: "Ben Davis",
		time: "12:18"
	},
	{
		id: "b6VhN_HHDiQ",
		title: "Build a Multi-Tenanted, Role-Based Access Control System",
		description: "TomDoesTech",
		time: "2:01:29"
	},
	/*
	This video became private
	Uncomment (in other files too) it when it becomes public again
	{
		id: "3tl9XCiQErA",
		title: "The Prisma killer is finally here",
		description: "SST",
		time: "5:42"
	},
	*/
	{
		id: "VQFjyEa8vGE",
		title: "Learning Drizzle ORM and working on a next14 project",
		description: "Web Dev Cody",
		time: "1:07:41"
	},
	{
		id: "5G0upg4sxgE",
		title: "This Trick Makes My Favorite Database Tool Even Better",
		description: "Josh tried coding",
		time: "6:01"
	},
	{
		id: "-JnEuvPmt-Q",
		title: "Effortless Auth in Next.js 14: Use Auth.js & Drizzle ORM for Secure Login",
		description: "Sam Meech-Ward",
		time: "26:29"
	},
]} />


Source: https://orm.drizzle.team/docs/mysql/perf-queries

# Query performance
When it comes to **Drizzle** — we're a thin TypeScript layer on top of SQL with 
almost 0 overhead and to make it actual 0, you can utilise our prepared statements API.
  
**When you run a query on the database, there are several things that happen:**
- all the configurations of the query builder got concatenated to the SQL string
- that string and params are sent to the database driver
- driver compiles SQL query to the binary SQL executable format and sends it to the database

With prepared statements you do SQL concatenation once on the Drizzle ORM side and then database 
driver is able to reuse precompiled binary SQL instead of parsing query all the time. 
It has extreme performance benefits on large SQL queries.  

Different database drivers support prepared statements in different ways and sometimes 
Drizzle ORM you can go [**faster than better-sqlite3 driver.**](https://twitter.com/_alexblokh/status/1593593415907909634)

## Prepared statement

```typescript copy {3}
    const db = drizzle(...);

    const prepared = db.select().from(customers).prepare();
    
    const res1 = await prepared.execute();
    const res2 = await prepared.execute();
    const res3 = await prepared.execute();
    ```

## Placeholder
Whenever you need to embed a dynamic runtime value - you can use the `sql.placeholder(...)` api

	```ts copy {6,9-10,15,18}
    import { sql, eq } from "drizzle-orm";

    const p1 = db
      .select()
      .from(customers)
      .where(eq(customers.id, sql.placeholder('id')))
      .prepare()

    await p1.execute({ id: 10 }) // SELECT * FROM customers WHERE id = 10
    await p1.execute({ id: 12 }) // SELECT * FROM customers WHERE id = 12

    const p2 = db
      .select()
      .from(customers)
      .where(sql`${customers.name} like ${sql.placeholder('name')}`)
      .prepare();

    await p2.execute({ name: '%an%' }) // SELECT * FROM customers WHERE name like '%an%'
    ```


Source: https://orm.drizzle.team/docs/mysql/query-utils

import $count from '@mdx/$count-mysql.mdx';

# Drizzle query utils

### $count
<$count/>



Source: https://orm.drizzle.team/docs/mysql/read-replicas

# Read Replicas

When your project involves a set of read replica instances, and you require a convenient method for managing 
SELECT queries from read replicas, as well as performing create, delete, and update operations on the primary 
instance, you can leverage the `withReplicas()` function within Drizzle

```ts copy
import { drizzle } from "drizzle-orm/mysql2";
import mysql from "mysql2/promise";
import { boolean, int, mysqlTable, text, withReplicas } from 'drizzle-orm/mysql-core';

const usersTable = mysqlTable('users', {
	id: int().primaryKey().autoincrement(),
	name: text().notNull(),
	verified: boolean().notNull().default(false),
});

const primaryClient = await mysql.createConnection({
  host: "host",
  user: "user",
  database: "primary_db",
})
const primaryDb = drizzle({ client: primaryClient });

const read1Client = await mysql.createConnection({
  host: "host",
  user: "user",
  database: "read_1",
})
const read1 = drizzle({ client: read1Client });

const read2Client = await mysql.createConnection({
  host: "host",
  user: "user",
  database: "read_2",
})
const read2 = drizzle({ client: read2Client });

const db = withReplicas(primaryDb, [read1, read2]);
```

You can now use the `db` instance the same way you did before. Drizzle will 
handle the choice between read replica and the primary instance automatically

```ts
// Read from either the read1 connection or the read2 connection
await db.select().from(usersTable)

// Use the primary database for the delete operation
await db.delete(usersTable).where(eq(usersTable.id, 1))
```

You can use the `$primary` key to force using primary instances even for read operations

```ts
// read from primary
await db.$primary.select().from(usersTable);
```

With Drizzle, you can also specify custom logic for choosing read replicas. 
You can make a weighted decision or any other custom selection method for random read replica choice. 
Here is an 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 selected.

Keep in mind that you can implement any type of random selection method 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]!
});

await db.select().from(usersTable)
```


Source: https://orm.drizzle.team/docs/mysql/relations-schema-declaration

import Tab from '@mdx/Tab.astro';
import Tabs from '@mdx/Tabs.astro';
import Callout from '@mdx/Callout.astro';
import SimpleLinkCards from '@mdx/SimpleLinkCards.astro';
import CodeTabs from "@mdx/CodeTabs.astro";
import Section from '@mdx/Section.astro';
import Flex from "@mdx/Flex.astro"
import LinksList from "@mdx/LinksList.astro"

# Drizzle Relations Fundamentals

In the world of databases, especially relational databases, the concept of relations is absolutely fundamental.
Think of "relations" as the connections and links between different pieces of data. Just like in real life, 
where people have relationships with each other, or objects are related to categories, databases use relations to model how different 
types of information are connected and work together.

### Normalization
Normalization is the process of organizing data in your database to reduce redundancy (duplication) and improve data integrity 
(accuracy and consistency). Think of it like tidying up a messy filing cabinet. Instead of having all sorts of papers 
crammed into one folder, you organize them into logical folders and categories to make everything easier to find and manage.

<Callout collapsed="Why is Normalization Important?">
- **Reduces Data Redundancy**: Imagine storing a customer's address every time they place an order. If the address changes, you'd have to update it in multiple places! Normalization helps you store information in one place and refer to it from other places, minimizing repetition.
- **Improves Data Integrity**: Less redundancy means less chance of inconsistencies. If you update an address in one place, it's updated everywhere it's needed.
- **Prevents Anomalies**: Normalization helps prevent issues like:
  1. **Insertion Anomalies**: Difficulty adding new data because you're missing related information.
  2. **Update Anomalies**: Having to update the same information in multiple rows.
  3. **Deletion Anomalies**: Accidentally losing valuable information when you delete something seemingly unrelated.
- **Easier to Understand and Maintain**: A normalized database is generally more logically structured and easier to understand, query, and modify.
</Callout>

Normalization is often described in terms of "normal forms" (1NF, 2NF, 3NF, and beyond). While the details can get quite technical, the core ideas are straightforward:

#### 1NF (First Normal Form): `Atomic Values`

**Goal**: Each column should hold a single, indivisible value. No repeating groups of data within a single cell

**Example**: Instead of having a single `address` column that stores `123 Main St, City, USA`, you'd 
break it down into separate columns: `street_address`, `city`, `state`, `zip_code`.

```sql
-- Unnormalized (violates 1NF)
CREATE TABLE `Customers_Unnormalized` (
    `customer_id` INT PRIMARY KEY,
    `name` VARCHAR(255),
    `address` VARCHAR(255) -- Problem: Multiple pieces of info in one column
);

-- Normalized to 1NF
CREATE TABLE `Customers_1NF` (
    `customer_id` INT PRIMARY KEY,
    `name` VARCHAR(255),
    `street_address` VARCHAR(255),
    `city` VARCHAR(255),
    `state` VARCHAR(255),
    `zip_code` VARCHAR(10)
);
```

#### 2NF (Second Normal Form): `Eliminate Redundant Data Dependent on Part of the Key`

**Goal**: Applies when you have a table with a composite primary key (a primary key made up of two or more columns). 
2NF ensures that all non-key attributes are fully dependent on the entire composite primary key, not just part of it.

Imagine we have a table called `order_items`. This table tracks items within orders, and we use a composite primary key (`order_id`, `product_id`) 
because a single order can have multiple of the same product (though in this simplified example, let's assume each product appears only 
once per order for clarity, but the composite key logic still applies).

<Callout collapsed="Expand for visual example">
```sql
CREATE TABLE `OrderItems_Unnormalized` (
    `order_id` INT,
    `product_id` VARCHAR(10),
    `product_name` VARCHAR(100),
    `product_price` DECIMAL(10, 2),
    `quantity` INT,
    `order_date` DATE,
    PRIMARY KEY (`order_id`, `product_id`) -- Composite Primary Key
);

INSERT INTO `OrderItems_Unnormalized` (`order_id`, `product_id`, `product_name`, `product_price`, `quantity`, `order_date`) VALUES
(101, 'A123', 'Laptop', 1200.00, 1, '2023-10-27'),
(101, 'B456', 'Mouse', 25.00, 2, '2023-10-27'),
(102, 'A123', 'Laptop', 1200.00, 1, '2023-10-28'),
(103, 'C789', 'Keyboard', 75.00, 1, '2023-10-29');
```
```
+------------------------------------------------------------------------------------+
| OrderItems_Unnormalized                                                            |
+------------------------------------------------------------------------------------+
| PK (order_id, product_id) | product_name | product_price | quantity | order_date   |
+------------------------------------------------------------------------------------+
| 101, A123               | Laptop       | 1200.00       | 1        | 2023-10-27     |
| 101, B456               | Mouse        | 25.00         | 2        | 2023-10-27     |
| 102, A123               | Laptop       | 1200.00       | 1        | 2023-10-28     |
| 103, C789               | Keyboard     | 75.00         | 1        | 2023-10-29     |
+------------------------------------------------------------------------------------+
```
</Callout>

**Problem**: Notice that `product_name` and `product_price` are repeated whenever the same `product_id` appears in different orders. 
These attributes are only dependent on `product_id`, which is part of the composite primary key (`order_id`, `product_id`), but not the entire key. 
This is a partial dependency.

To achieve 2NF, we need to remove the partially dependent attributes (`product_name`, `product_price`) and place them in a separate table where they are 
fully dependent on the primary key of that new table.

<Callout collapsed="Normalization to 2NF: Visual explanation">
```
+-------------------+     1:M     +---------------------------+
| Products          | <---------- | OrderItems_2NF            |
+-------------------+             +---------------------------+
| PK product_id     |             | PK (order_id, product_id) |
| product_name      |             | quantity                  |
| product_price     |             | order_date                |
+-------------------+             | FK product_id             |
                                  +---------------------------+
```
```sql
CREATE TABLE `Products` (
    `product_id` VARCHAR(10) PRIMARY KEY,
    `product_name` VARCHAR(100),
    `product_price` DECIMAL(10, 2)
);

CREATE TABLE `OrderItems_2NF` (
    `order_id` INT,
    `product_id` VARCHAR(10),
    `quantity` INT,
    `order_date` DATE,
    PRIMARY KEY (`order_id`, `product_id`), -- Composite Primary Key remains
    FOREIGN KEY (`product_id`) REFERENCES `Products`(`product_id`) -- Foreign Key to Products
);

-- Insert data into Products
INSERT INTO `Products` (`product_id`, `product_name`, `product_price`) VALUES
('A123', 'Laptop', 1200.00),
('B456', 'Mouse', 25.00),
('C789', 'Keyboard', 75.00);

-- Insert data into OrderItems_2NF (referencing Products)
INSERT INTO `OrderItems_2NF` (`order_id`, `product_id`, `quantity`, `order_date`) VALUES
(101, 'A123', 1, '2023-10-27'),
(101, 'B456', 2, '2023-10-27'),
(102, 'A123', 1, '2023-10-28'),
(103, 'C789', 1, '2023-10-29');
```
</Callout>

#### 3NF (Third Normal Form): `Eliminate Redundant Data Dependent on Non-Key Attributes`

**Goal**: Remove data that is dependent on other non-key attributes. This is about eliminating transitive dependencies.

**Problem**: Let's say we have a `suppliers` table. We store supplier information, including their `zip_code`, `city`, and `state`. `supplier_id` is the primary key.

<Callout collapsed="">
```sql
CREATE TABLE `suppliers` (
    `supplier_id` VARCHAR(10) PRIMARY KEY,
    `supplier_name` VARCHAR(255),
    `zip_code` VARCHAR(10),
    `city` VARCHAR(100),
    `state` VARCHAR(50)
);

INSERT INTO `suppliers` (`supplier_id`, `supplier_name`, `zip_code`, `city`, `state`) VALUES
('S1', 'Acme Corp', '12345', 'Anytown', 'NY'),
('S2', 'Beta Inc', '67890', 'Otherville', 'CA'),
('S3', 'Gamma Ltd', '12345', 'Anytown', 'NY');
```
```
+---------------------------------------------------------------+
| suppliers                                                     |
+---------------------------------------------------------------+
| PK supplier_id | supplier_name | zip_code | city      | state |
+---------------------------------------------------------------+
| S1             | Acme Corp     | 12345    | Anytown    | NY   |
| S2             | Beta Inc      | 67890    | Otherville | CA   |
| S3             | Gamma Ltd     | 12345    | Anytown    | NY   |
+---------------------------------------------------------------+
```
</Callout>

**Solution**: To achieve 3NF, we remove the attributes dependent on the non-key attribute (`city`, `state` dependent on `zip_code`) and put 
them into a separate table keyed by the non-key attribute itself (`zip_code`).

<Callout collapsed="Normalization to 3NF: Visual explanation">
```
+-------------------+     1:M     +--------------------+
| zip_codes         | <---------- | suppliers          |
+-------------------+             +--------------------+
| PK zip_code       |             | PK supplier_id     |
| city              |             | supplier_name      |
| state             |             | FK zip_code        |
+-------------------+             +--------------------+
```
```sql
CREATE TABLE `zip_codes` (
    `zip_code` VARCHAR(10) PRIMARY KEY,
    `city` VARCHAR(100),
    `state` VARCHAR(50)
);

CREATE TABLE `suppliers` (
    `supplier_id` VARCHAR(10) PRIMARY KEY,
    `supplier_name` VARCHAR(255),
    `zip_code` VARCHAR(10), -- Foreign Key to zip_codes
    FOREIGN KEY (`zip_code`) REFERENCES `zip_codes`(`zip_code`)
);

-- Insert data into zip_codes
INSERT INTO `zip_codes` (`zip_code`, `city`, `state`) VALUES
('12345', 'Anytown', 'NY'),
('67890', 'Otherville', 'CA');

-- Insert data into suppliers (referencing zip_codes)
INSERT INTO `suppliers` (`supplier_id`, `supplier_name`, `zip_code`) VALUES
('S1', 'Acme Corp', '12345'),
('S2', 'Beta Inc', '67890'),
('S3', 'Gamma Ltd', '12345');
```
</Callout>

<Callout title="Good to know">
There are additional normal forms, such as `4NF`, `5NF`, `6NF`, `EKNF`, `ETNF`, and `DKNF`. We won't cover these here, but we will create a 
dedicated set of tutorials for them in our guides and tutorials section.
</Callout>

### Database Relationships
#### One-to-One

In a one-to-one relationship, each record in `table A` is related to at most one record in `table B`, and each record in `table B` is
related to at most one record in `table A`. It's a very direct, exclusive pairing.

<Callout collapsed="Use Cases & Examples">
1. **User Profiles and User Account Details**: Think of a website. Each user account (in a Users table) might have exactly one user profile (in a UserProfiles table) containing more detailed information.
2. **Employees and Parking Spaces**: An Employees table and a ParkingSpaces table. Each employee might be assigned at most one parking space, and each parking space is assigned to at most one employee.
3. **Splitting Tables for Organization**: Sometimes, you might split a very wide table into two for better organization or security reasons, maintaining a 1-1 relationship between them.

```
Table A (One Side)      Table B (One Side)
+---------+             +---------+
| PK (A)  | <---------> | FK (A)  | (Foreign Key referencing Table A)
| ...     |             | ...     |
+---------+             +---------+
```
</Callout>


#### One-to-Many

In a one-to-many relationship, one record in `table A` can be related to many records in `table B`, but each 
record in `table B` is related to at most one record in `table A`. Think of it as a "parent-child" relationship.

<Callout collapsed="Use Cases & Examples">
1. **Customers and Orders**: One customer can place many orders, but each order belongs to only one customer.
2. **Authors and Books**: One author can write many books, but (let's simplify for now and say) each book is written by one primary author.
3. **Departments and Employees**: One department can have many employees, but each employee belongs to only one department.

```
Table A (One Side)      Table B (Many Side)
+---------+             +---------+
| PK (A)  | ----------> | FK (A)  | (Foreign Key referencing Table A)
| ...     |             | ...     |
+---------+             +---------+
     (One)                  (Many)
```
</Callout>

#### Many-to-Many

In a many-to-many relationship, one record in `table A` can be related to many records in `table B`, and one 
record in `table B` can be related to many records in `table A`. It's a more complex, bidirectional relationship.

<Callout collapsed="Use Cases & Examples">
1. **Students and Courses**: One student can enroll in many courses, and one course can have many students enrolled.
2. **Products and Categories**: One product can belong to multiple categories (e.g., a "T-shirt" can be
in "Clothing" and "Summer Wear" categories), and one category can contain many products.
3. **Authors and Books**: A book can be written by multiple authors, and an author can write multiple books.

```
Table A (Many Side)    Junction Table      Table B (Many Side)
+---------+          +-------------+     +---------+
| PK (A)  | -------->| FK (A)      | <----| FK (B)  |
| ...     |          | FK (B)      |     | ...     |
+---------+          +-------------+     +---------+
     (Many)             (Junction)          (Many)
```
</Callout>

Many-to-many relationships are not directly implemented with foreign keys between the two main tables. 
Instead, you need a `junction` table (also called an associative table or bridging table). 
This table acts as an intermediary to link records from both tables.

```sql
-- Table for Students (Many side)
CREATE TABLE `students` (
    `id` INT PRIMARY KEY,
    `name` VARCHAR(255)
);

-- Table for Courses (Many side)
CREATE TABLE `courses` (
    `id` INT PRIMARY KEY,
    `name` VARCHAR(255),
    `credits` INT
);

-- Junction Table: Enrollments (Connects Students and Courses - M-M relationship)
CREATE TABLE `enrollments` (
    `id` INT PRIMARY KEY AUTO_INCREMENT, -- Optional, but good practice for junction tables
    `student_id` INT,
    `course_id` INT,
    `enrollment_date` DATE,
    -- Composite Foreign Keys (often part of a composite primary key or unique constraint)
    FOREIGN KEY (`student_id`) REFERENCES `students`(`id`),
    FOREIGN KEY (`course_id`) REFERENCES `courses`(`id`),
    UNIQUE KEY (`student_id`, `course_id`) -- Prevent duplicate enrollments for the same student and course
);
```

### Why Foreign Keys?

You might think of foreign key constraints as simply a way to validate data - ensuring 
that when you enter a value in a foreign key column, that value actually exists in the primary key 
column of another table. And you'd be partially right! This value checking is the mechanism foreign keys use.

But it's crucial to understand that this validation is not the end goal, it's the means 
to a much larger purpose. Foreign key constraints are fundamentally about:

<Callout collapsed="1. Explicitly Defining and Enforcing Relationships">

We've discussed relationships like `One-to-Many` between Customers and Orders. 
A foreign key is the SQL language's way of telling the database: 

> Hey database, I want to enforce a 1-M relationship here. Every value in the customer_id column of the
Orders table must correspond to a valid customer_id in the Customers table.

It's not just a suggestion; it's a constraint the database actively enforces. 
The database becomes relationship-aware because of the foreign key.
</Callout>

<Callout collapsed="2. Maintaining Referential Integrity">
- This is the core of "data integrity" in the context of relationships. Referential integrity means 
that relationships between tables remain consistent and valid over time.
- Foreign keys prevent orphaned records. What's an orphaned record? In our Customer-Order example, 
an order that exists in the Orders table but doesn't have a corresponding customer in the Customers 
table would be an orphan. Foreign keys prevent this from happening (or control what happens 
if you try to delete a customer with orders - via CASCADE, SET NULL, etc.).
- Why is preventing orphans important? Orphaned records break the logical structure of your data. 
If you have an order without a customer, you lose crucial context. Queries become unreliable, reports
 become inaccurate, and your application's logic can break down.

**Example**:
```
Without a foreign key, you could accidentally delete a customer from the Customers 
table while their orders still exist in the Orders table. Suddenly, you have orders that point to 
a customer that no longer exists! A foreign key constraint prevents this data inconsistency.
```
</Callout>

<Callout collapsed="3. Facilitating Database Design and Understanding">
- Foreign keys are not just about technical enforcement; they are also a crucial part of database design documentation.
- When you see a foreign key in a database schema, it immediately tells you: 
`Table 'X' is related to Table 'Y' in this way.` It's a clear visual and structural indicator of relationships.
- This makes databases easier to understand, maintain, and evolve over time. New developers can quickly 
grasp how different parts of the database are connected.
</Callout>

In essence, foreign key constraints are not just about checking values; they are about:

1. Defining the rules of your data relationships
2. Actively enforcing those rules at the database level
3. Guaranteeing data integrity and consistency within those relationships
4. Making your database more robust, reliable, and understandable

### Why NOT Foreign Keys?

While highly beneficial, there are some scenarios where you might reconsider or use Foreign Keys with caution. 
These are typically edge cases and often involve trade-offs.

<Callout collapsed="1. Performance Overhead in Very High-Write Environments">
- **Scenario**: Extremely high-volume transactional systems (e.g., real-time logging, very high-frequency trading
platforms, massive IoT data ingestion).
- **Explanation**: Every time you insert or update data in a table with a foreign key, the database system 
needs to perform checks to ensure referential integrity. In extremely high-write scenarios, these 
checks can introduce a small but potentially noticeable performance overhead.
</Callout>

<Callout collapsed="2. Distributed Database Systems and Cross-Node Foreign Keys:">
- **Scenario**: Systems where data is distributed across multiple database nodes or clusters (common in sharded databases, cloud environments, and microservices).
- **Explanation**:  Cross-node foreign keys can introduce significant complexity and performance overhead. Validating referential integrity requires communication between nodes, leading to increased latency. Distributed transactions needed to maintain consistency are also more complex and can be less performant than local transactions. In such architectures, application-level data integrity checks or eventual consistency models might be considered alternatives.
</Callout>

<Callout collapsed="3. Legacy Systems and Data Integration with Non-Relational Data:">
- **Scenario**: Integrating a relational database with older legacy systems or non-relational data stores (e.g., NoSQL, flat files, external APIs).
- **Explanation**:  Legacy systems or non-relational data might not consistently adhere to the referential integrity rules enforced by foreign keys.  Imposing foreign keys in such scenarios can lead to data import issues, data inconsistencies, and might necessitate complex data transformation or application-level integrity management instead. You might need to carefully evaluate the data quality and consistency of the external sources and potentially rely on application logic or ETL processes to ensure data integrity instead of strictly enforcing foreign keys at the database level.
</Callout>

You can also check out some great explanations from the PlanetScale team in their [article](https://planetscale.com/docs/learn/operating-without-foreign-key-constraints#why-does-planetscale-not-recommend-constraints)

### Polymorphic Relations

Polymorphic relationships are a more advanced concept that allows a single relationship to point to 
different types of entities or tables. It's about creating more flexible and adaptable relationships when 
you have different kinds of data that share some commonality.

Imagine you have an `activities` log. An activity could be a `comment` a `like` or a `share`.
Each of these `activity` types has different details. Instead of creating separate tables and 
relationships for each activity type and the things they relate to, you might use a polymorphic approach.

<Callout collapsed="Common Scenarios & Examples">
- **Comments/Reviews**: A "Comment" might be related to different types of content: articles, products, videos, etc. 
Instead of having separate article_id, product_id, video_id columns in a Comments table, you can use a 
polymorphic relationship.
```
+---------------------+
| **Comments**        |
+---------------------+
| PK comment_id       |
| commentable_type    | ------>  [Polymorphic Relationship]
| commentable_id      | -------->
| user_id             |
| comment_text        |
| ...                 |
+---------------------+
          ^
          |
+---------------------+    +---------------------+    +---------------------+
| **Articles**        |    | **Products**        |    | **Videos**          |
+---------------------+    +---------------------+    +---------------------+
| PK article_id       |    | PK product_id       |    | PK video_id         |
| ...                 |    | ...                 |    | ...                 |
+---------------------+    +---------------------+    +---------------------+
```
- **Notifications:** A notification could be related to a user, an order, a system event, etc.
```
+----------------------+
| **Notifications**    |
+----------------------+
| PK notification_id  |
| notifiable_type     | ------>  [Polymorphic Relationship]
| notifiable_id       | -------->
| user_id             |
| message             |
| ...                  |
+----------------------+
           ^
           |
+---------------------+    +---------------------+    +-----------------------+
| **Users**           |    | **Orders**          |    | **System Events**     |
+---------------------+    +---------------------+    +-----------------------+
| PK user_id          |    | PK order_id         |    | PK event_id           |
| ...                 |    | ...                 |    | ...                   |
+---------------------+    +---------------------+    +-----------------------+
```
</Callout>

Polymorphic relationships are more complex and are often handled at the application level or 
using more advanced database features (depending on the specific database system). Standard SQL doesn't 
have direct, built-in support for enforcing polymorphic foreign key constraints in the same way as regular foreign keys.

Source: https://orm.drizzle.team/docs/mysql/relations-v1-v2

import Callout from '@mdx/Callout.astro';
import Prerequisites from "@mdx/Prerequisites.astro";
import Section from '@mdx/Section.astro';
import Npx from "@mdx/Npx.astro";
import Npm from "@mdx/Npm.astro";
import CodeTabs from '@mdx/CodeTabs.astro';
import CodeTab from '@mdx/CodeTab.astro';

# Migrating to Relational Queries version 2

<Npm>
 drizzle-orm@rc
 drizzle-kit@rc -D
</Npm>

<br/>

<Prerequisites>
- **Relations Fundamentals** - [read here](/docs/mysql/relations-schema-declaration)
- **drizzle-kit pull** - [read here](/docs/mysql/drizzle-kit-pull)
</Prerequisites>

<Callout>
Below is the table of contents. Click an item to jump to that section:

- [What is working differently from v1](#what-is-working-differently-from-v1)  
- [New features in v2](#what-is-new)  
- [How to migrate relations definition from v1 to v2](#how-to-migrate-relations-schema-definition-from-v1-to-v2)  
- [How to migrate queries from v1 to v2](#how-to-migrate-queries-from-v1-to-v2)  
- [Internal changes(imports, internal types, etc.)](#internal-changes)
</Callout>

### API changes
#### What is working differently from v1

{/* ##### Drizzle Relations schema definition */}

One of the biggest updates were in **Relations Schema definition**

The first difference is that you no longer need to specify `relations` for each table separately in different objects and
then pass them all to `drizzle()` along with your schema. In Relational Queries v2, you now have one dedicated place to
specify all the relations for all the tables you need.

The `r` parameter in the callback provides comprehensive autocomplete
functionality - including all tables from your schema and functions such as `one`, `many`, and `through` - essentially
offering everything you need to specify your relations.

```ts
// relations.ts
import * as schema from "./schema"
import { defineRelations } from "drizzle-orm"

export const relations = defineRelations(schema, (r) => ({
    ...
}));
```
```ts
// index.ts
import { relations } from "./relations"
import { drizzle } from "drizzle-orm/mysql2"

const db = drizzle(process.env.DATABASE_URL, { relations })
```

##### What is different?

<Callout collapsed="Schema Definition">
```ts copy
import * as p from 'drizzle-orm/mysql-core';

export const users = p.mysqlTable('users', {
  id: p.int().primaryKey(),
  name: p.text(),
  invitedBy: p.int('invited_by'),
});

export const posts = p.mysqlTable('posts', {
  id: p.int().primaryKey(),
  content: p.text(),
  authorId: p.int('author_id'),
});
```
</Callout>

**One place for all your relations**

<Callout title="❌ v1">
```ts
import { relations } from "drizzle-orm/_relations";
import { users, posts } from './schema';

export const usersRelation = relations(users, ({ one, many }) => ({
  invitee: one(users, {
    fields: [users.invitedBy],
    references: [users.id],
  }),
  posts: many(posts),
}));

export const postsRelation = relations(posts, ({ one, many }) => ({
  author: one(users, {
    fields: [posts.authorId],
    references: [users.id],
  }),
}));
```
</Callout>

<Callout title='✅ v2'>
```ts
import { defineRelations } from "drizzle-orm";
import * as schema from "./schema";

export const relations = defineRelations(schema, (r) => ({
  users: {
    invitee: r.one.users({
      from: r.users.invitedBy,
      to: r.users.id,
    }),
    posts: r.many.posts(),
  },
  posts: {
    author: r.one.users({
      from: r.posts.authorId,
      to: r.users.id,
    }),
  },
}));
```
</Callout>

You can still separate it into different `parts`, and you can make the parts any size you want

```ts
import { defineRelations, defineRelationsPart } from 'drizzle-orm';
import * as schema from "./schema";

export const relations = defineRelations(schema, (r) => ({
  users: {
    invitee: r.one.users({
      from: r.users.invitedBy,
      to: r.users.id,
    }),
    posts: r.many.posts(),
  }
}));

export const part = defineRelationsPart(schema, (r) => ({
  posts: {
    author: r.one.users({
      from: r.posts.authorId,
      to: r.users.id,
    }),
  }
}));
```

and then you can provide it to the db instance

```ts
const db = drizzle(process.env.DB_URL, { relations: { ...relations, ...part } })
```

**Define `many` without `one`**

In v1, if you wanted only the `many` side of a relationship, you had to specify the `one` side on the other end, 
which made for a poor developer experience.

In v2, you can simply use the `many` side without any additional steps

<Callout title="❌ v1">
```ts
import { relations } from "drizzle-orm/_relations";
import { users, posts } from './schema';

export const usersRelation = relations(users, ({ one, many }) => ({
  posts: many(posts),
}));

export const postsRelation = relations(posts, ({ one, many }) => ({
  author: one(users, {
    fields: [posts.authorId],
    references: [users.id],
  }),
}));
```
</Callout>

<Callout title='✅ v2'>
```ts
import { defineRelations } from "drizzle-orm";
import * as schema from "./schema";

export const relations = defineRelations(schema, (r) => ({
  users: {
    posts: r.many.posts({
      from: r.users.id,
      to: r.posts.authorId,
    }),
  },
}));
```
</Callout>

**New `optional` option**

`optional: false` at the type level makes the `author` key in the `posts` object required. 
This should be used when you are certain that this specific entity will always exist.

<Callout title="❌ v1">
Was not supported in v1
</Callout>

<Callout title='✅ v2'>
```ts {9}
import { defineRelations } from "drizzle-orm";
import * as schema from "./schema";

export const relations = defineRelations(schema, (r) => ({
  users: {
    posts: r.one.posts({
      from: r.users.id,
      to: r.posts.authorId,
      optional: false,
    }),
  },
}));
```
</Callout>

**No modes in `drizzle()`**

We found a way to use the same strategy for all MySQL dialects, so there's no need to specify them

<Callout title="❌ v1">
```ts
import * as schema from './schema'

const db = drizzle(process.env.DATABASE_URL, { mode: "planetscale", schema });
// or
const db = drizzle(process.env.DATABASE_URL, { mode: "default", schema });
```
</Callout>

<Callout title='✅ v2'>
```ts
import { relations } from './relations'

const db = drizzle(process.env.DATABASE_URL, { relations });
```
</Callout>

**`from` and `to` upgrades**

We've renamed `fields` to `from` and `references` to `to`, and we made both accept either a single value or an array

<Callout title="❌ v1">
```ts
...
author: one(users, {
  fields: [posts.authorId],
  references: [users.id],
}),
...
```
</Callout>

<Callout title='✅ v2'>
```ts
... 
author: r.one.users({
  from: r.posts.authorId,
  to: r.users.id,
}),
...
```
```ts
... 
author: r.one.users({
  from: [r.posts.authorId],
  to: [r.users.id],
}),
...
```
</Callout>

**`relationName` -> `alias`**

<Callout title="❌ v1">
```ts {8}
import { relations } from "drizzle-orm/_relations";
import { users, posts } from './schema';

export const postsRelation = relations(posts, ({ one }) => ({
  author: one(users, {
    fields: [posts.authorId],
    references: [users.id],
	  relationName: "author_post",
  }),
}));
```
</Callout>

<Callout title='✅ v2'>
```ts {9}
import { defineRelations } from "drizzle-orm";
import * as schema from "./schema";

export const relations = defineRelations(schema, (r) => ({
  posts: {
    author: r.one.users({
      from: r.posts.authorId,
      to: r.users.id,
      alias: "author_post",
    }),
  },
}));
```
</Callout>

**`custom types` new functions**

There are a few new function were added to custom types, so you can control how data is mapped on Relational Queries v2:

<Callout collapsed='fromJson'>
Optional mapping function, that is used for transforming data returned by transformed to JSON in database data to desired format
For example, when querying bigint column via [RQB](/docs/rqb) or JSON functions, the result field will be returned as it's string representation, as opposed to bigint from regular query
To handle that, we need a separate function to handle such field's mapping:
```ts
fromJson(value: string): bigint {
	return BigInt(value);
},
```
It'll cause the returned data to change from:
```ts
{
	customField: "5044565289845416380";
}
```
to:
```ts
{
	customField: 5044565289845416380n;
}
```
</Callout> 
<Callout collapsed='forJsonSelect'>
Optional selection modifier function, that is used for modifying selection of column inside JSON functions
Additional mapping that could be required for such scenarios can be handled using fromJson function
Used by [relational queries](/docs/rqb)

For example, when using bigint we need to cast field to text to preserve data integrity
```ts
forJsonSelect(identifier: SQL, sql: SQLGenerator, arrayDimensions?: number): SQL {
	return sql`${identifier}::text`
},
```
This will change query from:
```sql
SELECT
	row_to_json("t".*)
	FROM
	(
		SELECT
		"table"."custom_bigint" AS "bigint"
		FROM
		"table"
	) AS "t"
```
to:
```sql
SELECT
	row_to_json("t".*)
	FROM
	(
		SELECT
		"table"."custom_bigint"::text AS "bigint"
		FROM
		"table"
	) AS "t"
```
Returned by query object will change from:
```ts
{
	bigint: 5044565289845416000; // Partial data loss due to direct conversion to JSON format
}
```
to:
```ts
{
	bigint: "5044565289845416380"; // Data is preserved due to conversion of field to text before JSON-ification
}
```
</Callout>

<Callout title='✅ v2'>
```ts
const customBytes = customType<{
 	data: Buffer;
 	driverData: Buffer;
 	jsonData: string;
 }>({
 	dataType: () => 'bytea',
 	fromJson: (value) => {
 		return Buffer.from(value.slice(2, value.length), 'hex');
 	},
 	forJsonSelect: (identifier, sql, arrayDimensions) =>
 		sql`${identifier}::text${sql.raw('[]'.repeat(arrayDimensions ?? 0))}`,
 });
```

</Callout>

##### What is new?

**`through` for many-to-many relations**

Previously, you would need to query through a junction table and then map it out for every response

You don't need to do it now!

<Callout collapsed='Schema'>
```ts
import * as p from 'drizzle-orm/mysql-core';

export const users = p.mysqlTable('users', {
  id: p.int().primaryKey(),
  name: p.text(),
  verified: p.boolean().notNull(),
});

export const groups = p.mysqlTable('groups', {
  id: p.int().primaryKey(),
  name: p.text(),
});

export const usersToGroups = p.mysqlTable(
  'users_to_groups',
  {
    userId: p
      .int('user_id')
      .notNull()
      .references(() => users.id),
    groupId: p
      .int('group_id')
      .notNull()
      .references(() => groups.id),
  },
  (t) => [p.primaryKey({ columns: [t.userId, t.groupId] })],
);

```
</Callout>

<Callout title="❌ v1">
```ts
export const usersRelations = relations(users, ({ many }) => ({
  usersToGroups: many(usersToGroups),
}));

export const groupsRelations = relations(groups, ({ many }) => ({
  usersToGroups: many(usersToGroups),
}));

export const usersToGroupsRelations = relations(usersToGroups, ({ one }) => ({
  group: one(groups, {
    fields: [usersToGroups.groupId],
    references: [groups.id],
  }),
  user: one(users, {
    fields: [usersToGroups.userId],
    references: [users.id],
  }),
}));
```
```ts
// Query example
const response = await db.query.users.findMany({
  with: {
    usersToGroups: {
      columns: {},
      with: {
        group: true,
      },
    },
  },
});
```
</Callout>

<Callout title='✅ v2'>
```ts
import * as schema from './schema';
import { defineRelations } from 'drizzle-orm';

export const relations = defineRelations(schema, (r) => ({
  users: {
    groups: r.many.groups({
      from: r.users.id.through(r.usersToGroups.userId),
      to: r.groups.id.through(r.usersToGroups.groupId),
    }),
  },
  groups: {
    participants: r.many.users(),
  },
}));
```
```ts
// Query example
const response = await db.query.users.findMany({
  with: {
    groups: true,
  },
});
```
</Callout>

**Predefined filters**

<Callout title="❌ v1">
Was not supported in v1
</Callout>

<Callout title='✅ v2'>
```ts {10-12}
import * as schema from './schema';
import { defineRelations } from 'drizzle-orm';

export const relations = defineRelations(schema,
  (r) => ({
    groups: {
      verifiedUsers: r.many.users({
        from: r.groups.id.through(r.usersToGroups.groupId),
        to: r.users.id.through(r.usersToGroups.userId),
        where: {
          verified: true,
        },
      }),
    },
  })
);
```
```ts {4}
// Query example: get groups with all verified users
const response = await db.query.groups.findMany({
  with: {
    verifiedUsers: true,
  },
});
```
</Callout>

##### `where` is now object

<Callout title="❌ v1">
```ts
const response = db._query.users.findMany({
  where: (users, { eq }) => eq(users.id, 1),
});
```
</Callout>

<Callout title="✅ v2">
```ts
const response = db.query.users.findMany({
  where: {
    id: 1,
  },
});
```

For a complete API Reference please check our [Select Filters docs](/docs/mysql/rqb#select-filters)
</Callout>

<Callout collapsed='Complex filter example using RAW'>
```ts
// schema.ts
import { int, json, mysqlTable, text, timestamp } from 'drizzle-orm/mysql-core';

export const users = mysqlTable('users', {
  id: int().primaryKey(),
  name: text(),
  email: text().notNull(),
  age: int(),
  createdAt: timestamp('created_at').defaultNow(),
  lastLogin: timestamp('last_login'),
  subscriptionEnd: timestamp('subscription_end'),
  lastActivity: timestamp('last_activity'),
  preferences: json(), // JSON column for user settings/preferences
  interests: json().$type<string[]>(), // Array column for user interests
});
```
```ts
const response = await db.query.users.findMany({
    where: {
      AND: [
        {
          OR: [{ RAW: (table) => sql`${table.name} LIKE 'john%'` }, { name: { like: "jane%" } }],
        },
        { 
			RAW: (table) => sql`${table.age} BETWEEN 25 AND 35` 
		},
      ],
    },
  }),
```
</Callout>

##### `orderBy` is now object

<Callout title="❌ v1">
```ts
const response = db._query.users.findMany({
  orderBy: (users, { asc }) => [asc(users.id)],
});
```
</Callout>

<Callout title="✅ v2">
```ts
const response = db.query.users.findMany({
  orderBy: { id: "asc" },
});
```
</Callout>

##### Filtering by relations

<Callout title="❌ v1">
Was not supported in v1
</Callout>

<Callout title='✅ v2'>
Example: Get all users whose ID>10 and who have at least one post with content starting with “M”

```ts
const usersWithPosts = await db.query.usersTable.findMany({
  where: {
    id: {
      gt: 10
    },
    posts: {
      content: {
        like: 'M%'
      }
    }
  },
});
```
</Callout>

##### Using offset on related objects

<Callout title="❌ v1">
Was not supported in v1
</Callout>

<Callout title='✅ v2'>
```ts
await db.query.posts.findMany({
	limit: 5,
	offset: 2, // correct ✅
	with: {
		comments: {
			offset: 3, // correct ✅
			limit: 3,
		},
	},
});
```
</Callout>

#### How to migrate relations schema definition from v1 to v2

##### **Option 1**: Using `drizzle-kit pull`

In new version `drizzle-kit pull` supports pulling `relations.ts` file in a new syntax:

##### Step 1

<Npx>
drizzle-kit pull
</Npx>

#### Step 2 

Transfer generated relations code from `drizzle/relations.ts` to the file you are using to specify your relations 
```plaintext {4-5}
 ├ 📂 drizzle
 │ ├ 📂 meta
 │ ├ 📜 migration.sql
 │ ├ 📜 relations.ts ────────┐
 │ └ 📜 schema.ts            |
 ├ 📂 src                    │ 
 │ ├ 📂 db                   │
 │ │ ├ 📜 relations.ts <─────┘
 │ │ └ 📜 schema.ts 
 │ └ 📜 index.ts         
 └ …
```

<Callout>
`drizzle/relations.ts` includes an import of all tables from `drizzle/schema.ts`, which looks like this:
```ts
import * as schema from './schema'
```

You may need to change this import to a file where ALL your schema tables are located. 

If there are multiple schema files, you can do the following:
```ts
import * as schema1 from './schema1'
import * as schema2 from './schema2'
...
```
</Callout>

#### Step 3

Change drizzle database instance creation and provide `relations` object instead of `schema`

<Callout title='Before'>
```ts
import * as schema from './schema'
import { drizzle } from 'drizzle-orm/mysql2'

const db = drizzle('<url>', { schema })
```
</Callout>

<Callout title='After'>
```ts
// should be imported from a file in Step 2
import { relations } from './relations'
import { drizzle } from 'drizzle-orm/mysql2'

const db = drizzle('<url>', { relations })
```
</Callout>

<Callout>
If you had MySQL dialect, you can remove `mode` from `drizzle()` as long as it's not needed in version 2
</Callout>

##### **Option 2**: Manual migration

If you want to migrate manually, you can check our [Drizzle Relations section](/docs/mysql/relations) for the complete API reference and examples of one-to-one, one-to-many, and many-to-many relations.

#### How to migrate queries from v1 to v2

##### Migrate `where` statements

You can check our [Select Filters docs](/docs/mysql/rqb#select-filters) to see examples and a complete API reference.

With the new syntax, you can use `AND`, `OR`, `NOT`, and `RAW`, plus all the filtering operators that 
were previously available in Relations v1.

**Examples**
<CodeTabs items={["simple eq", "using AND", "using OR", "using NOT", "complex example using RAW"]}>
<CodeTab>
```ts
const response = await db.query.users.findMany({
  where: {
    age: 15,
  },
});
```
```sql {8}
SELECT
	`d0`.`id` AS `id`,
	`d0`.`name` AS `name`,
	`d0`.`age` AS `age`
FROM
	`users` AS `d0`
WHERE
	`d0`.`age` = 15;
```
</CodeTab>
<CodeTab>
```ts
const response = await db.query.users.findMany({
  where: {
    age: 15,
    name: 'John'
  },
});
```
```sql {9-10}
SELECT
	`d0`.`id` AS `id`,
	`d0`.`name` AS `name`,
	`d0`.`age` AS `age`
FROM
	`users` AS `d0`
WHERE
	(
		(`d0`.`age` = 15)
		AND (`d0`.`name` = 'John')
	);
```
</CodeTab>
<CodeTab>
```ts
const response = await db.query.users.findMany({
  where: {
    OR: [
      {
        id: {
          gt: 10,
        },
      },
      {
        name: {
          like: "John%",
        },
      },
    ],
  },
});
```
```sql {9-10}
SELECT
	`d0`.`id` AS `id`,
	`d0`.`name` AS `name`,
	`d0`.`age` AS `age`
FROM
	`users` AS `d0`
WHERE
	(
		(`d0`.`id` > 10)
		OR (`d0`.`name` LIKE 'John%')
	);
```
</CodeTab>
<CodeTab>
```ts
const response = await db.query.users.findMany({
  where: {
    NOT: {
      id: {
        gt: 10,
      },
    },
    name: {
      like: "John%",
    },
  },
});
```
```sql {9-10}
SELECT
	`d0`.`id` AS `id`,
	`d0`.`name` AS `name`,
	`d0`.`age` AS `age`
FROM
	`users` AS `d0`
WHERE
	(
		(not(`d0`.`id` > 10))
		AND (`d0`.`name` LIKE 'John%')
	);
```
</CodeTab>
<CodeTab>
```ts
// schema.ts
import { int, json, mysqlTable, text, timestamp } from "drizzle-orm/mysql-core";
import { sql } from "drizzle-orm";

export const users = mysqlTable("users", {
  id: int().primaryKey(),
  name: text(),
  email: text().notNull(),
  age: int(),
  createdAt: timestamp("created_at").defaultNow(),
  lastLogin: timestamp("last_login"),
  subscriptionEnd: timestamp("subscription_end"),
  lastActivity: timestamp("last_activity"),
  preferences: json(), // JSON column for user settings/preferences
  interests: json().$type<string[]>(), // Array column for user interests
});
```
```ts
const response = await db.query.users.findMany({
    where: {
      AND: [
        {
          OR: [{ RAW: (table) => sql`${table.name} LIKE 'john%'` }, { name: { like: "jane%" } }],
        },
        { 
			RAW: (table) => sql`${table.age} BETWEEN 25 AND 35` 
		},
      ],
    },
  }),
```
```sql
SELECT
	`d0`.`id` AS `id`,
	`d0`.`name` AS `name`,
	`d0`.`email` AS `email`,
	`d0`.`age` AS `age`,
	`d0`.`created_at` AS `createdAt`,
	`d0`.`last_login` AS `lastLogin`,
	`d0`.`subscription_end` AS `subscriptionEnd`,
	`d0`.`last_activity` AS `lastActivity`,
	`d0`.`preferences` AS `preferences`,
	`d0`.`interests` AS `interests`
FROM
	`users` AS `d0`
WHERE
	(
		(
			(
				(`d0`.`name` LIKE 'john%')
				OR (`d0`.`name` LIKE 'jane%')
			)
		)
		AND (`d0`.`age` BETWEEN 25 AND 35)
	);
```
</CodeTab>
</CodeTabs>

##### Migrate `orderBy` statements

Order by was simplified to a single object, where you specify the column and the sort direction (`asc` or `desc`)

<Callout title="❌ v1">
```ts
const response = db._query.users.findMany({
  orderBy: (users, { asc }) => [asc(users.id)],
});
```
</Callout>

<Callout title="✅ v2">
```ts
const response = db.query.users.findMany({
  orderBy: { id: "asc" },
});
```
</Callout>

##### Migrate `many-to-many` queries

Relational Queries v1 had a very complex way of managing many-to-many queries.
You had to use junction tables to query through them explicitly, and then map those tables out, like this:

```ts
const response = await db.query.users.findMany({
  with: {
    usersToGroups: {
      columns: {},
      with: {
        group: true,
      },
    },
  },
});
```

After upgrading to Relational Queries v2, your many-to-many relation will look like this:

```ts
import * as schema from './schema';
import { defineRelations } from 'drizzle-orm';

export const relations = defineRelations(schema, (r) => ({
  users: {
    groups: r.many.groups({
      from: r.users.id.through(r.usersToGroups.userId),
      to: r.groups.id.through(r.usersToGroups.groupId),
    }),
  },
  groups: {
    participants: r.many.users(),
  },
}));
```

And when you migrate your query, it will become this:

```ts
// Query example
const response = await db.query.users.findMany({
  with: {
    groups: true,
  },
});
```

### Internal changes

1. Every `drizzle` database, `session`, `migrator` and `transaction` instance updated with new generic arguments for RQB v2 queries

<Callout collapsed='Examples'>
**migrator**
<Callout type='error' title='before'>
```ts
export async function migrate<
  TSchema extends Record<string, unknown>
>(
  db: MySql2Database<TSchema>,
  config: MigrationConfig,
) {
  ...
}
```
</Callout>
<Callout title='now'>
```ts {1,2}
export async function migrate<TRelations extends AnyRelations>(
	db: MySql2Database<TRelations>,
	config: MigrationConfig,
) {
  ...
}
```
</Callout>
**session**
<Callout type='error' title='before'>
```ts
export class MySql2Session<
	TFullSchema extends Record<string, unknown>,
	TSchema extends V1.TablesRelationalConfig,
> extends MySqlSession<MySqlQueryResultHKT, MySql2PreparedQueryHKT, TFullSchema, TSchema>
```
</Callout>
<Callout title='now'>
```ts {2,3}
export class MySql2Session<
	TRelations extends AnyRelations,
> extends MySqlSession<MySqlQueryResultHKT, TRelations>
```
</Callout>
**transaction**
<Callout type='error' title='before'>
```ts
export class MySql2Transaction<
	TFullSchema extends Record<string, unknown>,
	TSchema extends V1.TablesRelationalConfig,
> extends MySqlTransaction<MySql2QueryResultHKT, MySql2PreparedQueryHKT, TFullSchema, TSchema>
```
</Callout>
<Callout title='now'>
```ts {2,3}
export class MySql2Transaction<
	TRelations extends AnyRelations,
> extends MySqlTransaction<MySql2QueryResultHKT, TRelations>
```
</Callout>
**driver**
<Callout type='error' title='before'>
```ts
export class MySql2Database<
	TSchema extends Record<string, unknown> = Record<string, never>,
> extends MySqlDatabase<MySql2QueryResultHKT, MySql2PreparedQueryHKT, TSchema>
```
</Callout>
<Callout title='now'>
```ts {2,3}
export class MySql2Database<
	TRelations extends AnyRelations = EmptyRelations,
> extends MySqlDatabase<MySql2QueryResultHKT, TRelations>
```
</Callout>
</Callout>

2. Updated `DrizzleConfig` generic with `TRelations` argument and `relations: TRelations` field

<Callout collapsed='Examples'>
<Callout type='error' title='before'>
```ts
export interface DrizzleConfig<
  TSchema extends Record<string, unknown> = Record<string, never>
> {
  logger?: boolean | Logger;
  schema?: TSchema;
  casing?: Casing;
}
```
</Callout>

<Callout title='now'>
```ts {2,5}
export interface DrizzleConfig<
	TRelationConfigs extends AnyRelations = EmptyRelations,
> {
	logger?: boolean | Logger | undefined;
	relations?: TRelationConfigs | undefined;
	cache?: Cache | undefined;
	jit?: boolean | undefined;
}
```
</Callout>
</Callout>

3. The following entities have been removed from `drizzle-orm` and `drizzle-orm/relations`. The original imports now 
include new types used by Relational Queries v2, so make sure to update your imports if you intend to use the older types:

<Callout collapsed='A list of all removed entities'>
- `Relations`
- `TableRelationsKeysOnly`
- `ExtractTableRelationsFromSchema`
- `ExtractRelationsFromTableExtraConfigSchema`
- `getOperators`
- `FindTableByDBName`
- `RelationalSchemaConfig`
- `RelationConfig`
- `extractTablesRelationalConfig`
- `relations`
- `createOne`
- `createMany`
- `NormalizedRelation`
- `normalizeRelation`
- `createTableRelationsHelpers`
- `TableRelationsHelpers`
</Callout>

4. In the same manner, `${dialect}-core/query-builders/query` files were updated with RQB v2's alternatives

<Callout collapsed='Examples'>
```ts
import { RelationalQueryBuilder, MySqlRelationalQuery } from 'drizzle-orm/mysql-core/query-builders/query';
```
</Callout>


Source: https://orm.drizzle.team/docs/mysql/relations

import Tab from '@mdx/Tab.astro';
import Tabs from '@mdx/Tabs.astro';
import IsSupportedChipGroup from '@mdx/IsSupportedChipGroup.astro';
import Callout from '@mdx/Callout.astro';
import Section from '@mdx/Section.astro';
import Prerequisites from "@mdx/Prerequisites.astro";
import CodeTab from '@mdx/CodeTab.astro';
import CodeTabs from '@mdx/CodeTabs.astro';
import Npm from '@mdx/Npm.astro';

# Drizzle relations

<Npm>
 drizzle-orm@rc
 drizzle-kit@rc -D
</Npm>

<br/>

<Prerequisites>  
  - **Relations Fundamentals** - get familiar with the concepts of foreign key constraints, soft relations, database normalization, etc - [read here](/docs/mysql/relations-schema-declaration)
  - **Declare schema** - get familiar with how to define drizzle schemas - [read here](/docs/mysql/sql-schema-declaration)
  - **Database connection** - get familiar with how to connect to database using drizzle - [read here](/docs/mysql/get-started-mysql)
</Prerequisites>

The sole purpose of Drizzle relations is to let you query your relational data in the most simple and concise way:

<CodeTabs items={["Relational queries", "Select with joins"]}>
<Section>
```ts
import { drizzle } from 'drizzle-orm/mysql2';
import { defineRelations } from 'drizzle-orm';
import * as p from 'drizzle-orm/mysql-core';

export const users = p.mysqlTable('users', {
	id: p.int().autoincrement().primaryKey(),
	name: p.text().notNull()
});

export const posts = p.mysqlTable('posts', {
	id: p.int().autoincrement().primaryKey(),
	content: p.text().notNull(),
	ownerId: p.int('owner_id'),
});

export const relations = defineRelations({ users, posts }, (r) => ({
	posts: {
		author: r.one.users({
			from: r.posts.ownerId,
			to: r.users.id,
		}),
	}
}))

const db = drizzle({ client, relations });

const result = await db.query.posts.findMany({
  with: {
    author: true,
  },
});
```
```ts
[{
  id: 10,
  content: "My first post!",
  ownerId: 14,
  author: {
    id: 1,
    name: "Alex"
  }
}]
```
</Section>
<Section>
```ts
import { drizzle } from 'drizzle-orm/mysql2';
import { eq } from 'drizzle-orm';
import * as p from "drizzle-orm/mysql-core";

export const users = p.mysqlTable('users', {
	id: p.int().autoincrement().primaryKey(),
	name: p.text().notNull()
});
export const posts = p.mysqlTable('posts', {
	id: p.int().autoincrement().primaryKey(),
	content: p.text().notNull(),
	ownerId: p.int('owner_id'),
});

const db = drizzle({ client });

const res = await db.select()
                    .from(posts)
                    .leftJoin(users, eq(posts.ownerId, users.id))
                    .orderBy(posts.id)

const mappedResult = ...
```
</Section>
</CodeTabs>

### `one()`
Here is a list of all fields available for `.one()` in drizzle relations

```ts {3-11}
const relations = defineRelations({ users, posts }, (r) => ({
	posts: {
		author: r.one.users({
			from: r.posts.ownerId,
			to: r.users.id,
			optional: false,
      alias: 'custom_name',
			where: {
				verified: true,
			}
		}),
	}
}))
```

- `author` key is a custom key that appears in the `posts` object when using Drizzle relational queries.
- `r.one.users` defines that `author` will be a single object from the `users` table rather than an array of objects.
- `from: r.posts.ownerId` specifies the table from which we are establishing a soft relation. 
In this case, the relation starts from the `ownerId` column in the `posts` table.
- `to: r.users.id` specifies the table to which we are establishing a soft relation. 
In this case, the relation points to the `id` column in the `users` table.
- `optional: false` at the type level makes the `author` key in the posts object `required`. 
This should be used when you are certain that this specific entity will always exist.
- `alias` is used to add a specific alias to relationships between tables. If you have multiple identical relationships between two tables, you should 
differentiate them using `alias`
- `where` condition can be used for polymorphic relations. It fetches relations based on a `where` statement.
For example, in the case above, only `verified authors` will be retrieved. Learn more about polymorphic relations [here](/docs/mysql/relations-schema-declaration#polymorphic-relations).

### `many()`

Here is a list of all fields available for `.many()` in drizzle relations

```ts {3-10}
const relations = defineRelations({ users, posts }, (r) => ({
	users: {
		feed: r.many.posts({
			from: r.users.id,
			to: r.posts.ownerId,
			alias: 'custom_name',
			where: {
				approved: true,
			}
		}),
	}
}))
```

- `feed` key is a custom key that appears in the `users` object when using Drizzle relational queries.
- `r.many.posts` defines that `feed` will be an array of objects from the `posts` table rather than just an object
- `from: r.users.id` specifies the table from which we are establishing a soft relation. 
In this case, the relation starts from the `id` column in the `users` table.
- `to: r.posts.ownerId` specifies the table to which we are establishing a soft relation. 
In this case, the relation points to the `ownerId` column in the `posts` table.
- `alias` is used to add a specific alias to relationships between tables. If you have multiple identical relationships between two tables, you should 
differentiate them using `alias`
- `where` condition can be used for polymorphic relations. It fetches relations based on a `where` statement.
For example, in the case above, only `approved posts` will be retrieved. Learn more about polymorphic relations [here](/docs/mysql/relations-schema-declaration#polymorphic-relations).

## ---

### One-to-one
Drizzle ORM provides you an API to define `one-to-one` relations between tables with the `defineRelations` function.

An example of a `one-to-one` relation between users and users, where a user can invite another (this example uses a self reference):

```typescript copy {10-17}
import { mysqlTable, text, int } from 'drizzle-orm/mysql-core';
import { defineRelations } from 'drizzle-orm';

export const users = mysqlTable('users', {
	id: int().autoincrement().primaryKey(),
	name: text(),
	invitedBy: int('invited_by'),
});

export const relations = defineRelations({ users }, (r) => ({
	users: {
		invitee: r.one.users({
			from: r.users.invitedBy,
			to: r.users.id,
		})
	}
}));
```

Another example would be a user having a profile information stored in separate table. In this case, because the foreign key is stored in the "profile_info" table, the user relation have neither fields or references. This tells Typescript that `user.profileInfo` is nullable:

```typescript copy {15-22}
import { mysqlTable, text, int, json } from 'drizzle-orm/mysql-core';
import { defineRelations } from 'drizzle-orm';

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

export const profileInfo = mysqlTable('profile_info', {
  id: int().autoincrement().primaryKey(),
  userId: int('user_id').references(() => users.id),
  metadata: json(),
});

export const relations = defineRelations({ users, profileInfo }, (r) => ({
  users: {
    profileInfo: r.one.profileInfo({
      from: r.users.id,
      to: r.profileInfo.userId,
    }),
  },
}));

const user = await db.query.users.findFirst({ with: { profileInfo: true } });
//____^? type { id: number, name: string | null, profileInfo: { ... } | null  }
```

### One-to-many
Drizzle ORM provides you an API to define `one-to-many` relations between tables with `defineRelations` function. 

Example of `one-to-many` relation between users and posts they've written:

```typescript copy {15-25}
import { mysqlTable, text, int } from 'drizzle-orm/mysql-core';
import { defineRelations } from 'drizzle-orm';

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

export const posts = mysqlTable('posts', {
  id: int().primaryKey(),
  content: text(),
  authorId: int('author_id'),
});

export const relations = defineRelations({ users, posts }, (r) => ({
  posts: {
    author: r.one.users({
      from: r.posts.authorId,
      to: r.users.id,
    }),
  },
  users: {
    posts: r.many.posts(),
  },
}));
```

Now lets add comments to the posts:
```typescript copy {9-14,22,27-32}
...

export const posts = mysqlTable('posts', {
	id: int().primaryKey(),
	content: text(),
	authorId: int('author_id'),
});

export const comments = mysqlTable('comments', {
  id: int().autoincrement().primaryKey(),
  text: text(),
  authorId: int('author_id'),
  postId: int('post_id'),
});

export const relations = defineRelations({ users, posts, comments }, (r) => ({
  posts: {
    author: r.one.users({
      from: r.posts.authorId,
      to: r.users.id,
    }),
    comments: r.many.comments(),
  },
  users: {
    posts: r.many.posts(),
  },
  comments: {
    post: r.one.posts({
      from: r.comments.postId,
      to: r.posts.id,
    }),
  },
}));
```


### Many-to-many
Drizzle ORM provides you an API to define `many-to-many` relations between tables through so called `junction` or `join` tables,
they have to be explicitly defined and store associations between related tables.  

Example of `many-to-many` relation between users and groups we are using `through` to bypass junction table selection and directly select many `groups` for each `user`.
```typescript copy {27-39}
import { defineRelations } from 'drizzle-orm';
import { int, mysqlTable, primaryKey, text } from 'drizzle-orm/mysql-core';

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

export const groups = mysqlTable('groups', {
  id: int().autoincrement().primaryKey(),
  name: text(),
});

export const usersToGroups = mysqlTable(
  'users_to_groups',
  {
    userId: int('user_id')
      .notNull()
      .references(() => users.id),
    groupId: int('group_id')
      .notNull()
      .references(() => groups.id),
  },
  (t) => [primaryKey({ columns: [t.userId, t.groupId] })],
);

export const relations = defineRelations({ users, groups, usersToGroups },
  (r) => ({
    users: {
      groups: r.many.groups({
        from: r.users.id.through(r.usersToGroups.userId),
        to: r.groups.id.through(r.usersToGroups.groupId),
      }),
    },
    groups: {
      participants: r.many.users(),
    },
  })
);
```

**Query example:**
```ts
const res = await db.query.users.findMany({
  with: { 
    groups: true 
  },
});

// response type
type Response = {
  id: number;
  name: string | null;
  groups: {
    id: number;
    name: string | null;
  }[];
}[];
```

### Predefined filters

Predefined `where` statements in Drizzle's relation definitions are a type of polymorphic relations implementation, but it's not fully it. Essentially, they allow you to
connect tables not only by selecting specific columns but also through custom `where` statements. Let's look at some examples:

We can define a relation between `groups` and `users` so that when querying group's users, we only retrieve those whose `verified` column is set to `true`
<CodeTabs items={["Relations", "Schema"]}>
<Section>
```ts
import { defineRelations } from "drizzle-orm";
import * as schema from './schema';

export const relations = defineRelations(schema,(r) => ({
    groups: {
      verifiedUsers: r.many.users({
        from: r.groups.id.through(r.usersToGroups.groupId),
        to: r.users.id.through(r.usersToGroups.userId),
        where: {
          verified: true,
        },
      }),
    },
  })
);

...

await db.query.groups.findMany({
    with: {
      verifiedUsers: true,
    },
});
```
</Section>
<Section>
```ts
import * as p from "drizzle-orm/mysql-core";

export const users = p.mysqlTable("users", {
  id: p.int().autoincrement().primaryKey(),
  name: p.text().notNull(),
  verified: p.boolean().notNull(),
});

export const groups = p.mysqlTable("groups", {
  id: p.int().autoincrement().primaryKey(),
  title: p.text().notNull(),
});

export const usersToGroups = p.mysqlTable(
  "users_to_groups",
  {
    userId: p
      .int("user_id")
      .notNull()
      .references(() => users.id, { onDelete: "cascade" }),
    groupId: p
      .int("group_id")
      .notNull()
      .references(() => groups.id, { onDelete: "cascade" }),
  },
  (t) => [p.primaryKey({ columns: [t.groupId, t.userId] })]
);
```
</Section>
</CodeTabs>

<Callout type='warning'>
You can only specify filters on the target (to) table. So in this example, the where clause will only include columns from the `users` table since we are establishing a relation **TO** users

```ts {7}
export const relations = defineRelations(schema,(r) => ({
    groups: {
      verifiedUsers: r.many.users({
        from: r.groups.id.through(r.usersToGroups.groupId),
        to: r.users.id.through(r.usersToGroups.userId),
        where: {
          verified: true,
        },
      }),
    },
  })
);
```
</Callout>

## ---

### Relations Parts

In a case you need to separate relations config into several parts you can use `defineRelationsPart` helpers

```ts
import { defineRelations, defineRelationsPart } from 'drizzle-orm';
import * as schema from "./schema";

export const relations = defineRelations(schema, (r) => ({
  users: {
    invitee: r.one.users({
      from: r.users.invitedBy,
      to: r.users.id,
    }),
    posts: r.many.posts(),
  }
}));

export const part = defineRelationsPart(schema, (r) => ({
  posts: {
    author: r.one.users({
      from: r.posts.authorId,
      to: r.users.id,
    }),
  }
}));
```

and then you can provide it to the db instance

```ts
const db = drizzle(process.env.DB_URL, { relations: { ...relations, ...part } })
```

<Callout type='warning'>
There are a few rules you would need to follow to make sure it `defineRelationsParts` works as expected

**Rule 1**: If you specify reltions with parts, when passing it to drizzle db function you would need to specify it in the right order(main relations goes first)
```ts
// ✅
const db = drizzle(process.env.DB_URL, { relations: { ...relations, ...part } })

// ❌
const db = drizzle(process.env.DB_URL, { relations: { ...part, ...relations } })
```

<Callout collapsed="Why it's important?">
Even if there will be no type or runtime error, this is how "..." works with objects. As long as main relation 
recursively infer all tables names, so it can be available in autocomplete. Here is an example:

```ts
export const relations = defineRelations(schema, (r) => ({
  users: {
    invitee: r.one.users({
      from: r.users.invitedBy,
      to: r.users.id,
    }),
    posts: r.many.posts(),
  }
}));

export const part = defineRelationsPart(schema, (r) => ({
  posts: {
    author: r.one.users({
      from: r.posts.authorId,
      to: r.users.id,
    }),
  }
}));
```

Here `relations` and `part` can be represented and this object:
```json
// relations
{
  "users": {"invitee": {...}, "posts": {...}},
  // added here, so all tables from schema will exist in autocomplete
  "posts": {}
}

// part
{
  "posts": {"author": {...}}
}
```

Having `{ ...relations, ...part }` will result in 
```json
{
  "users": {"invitee": {...}, "posts": {...}},
  "posts": {"author": {...}}
}
```

and having `{ ...relations, ...part }` will result in
```json
{
  "users": {"invitee": {...}, "posts": {...}},
  // As you can see in the final object, posts relations information will be lost
  "posts": {}
}
```

</Callout>

**Rule 2**: You should have min relations, so drizzle can infer all of the table for autocomplete. If you want to have only parts, then 
one of your parts should be empty, like this:

```ts
export const mainPart = defineRelationsPart(schema);
```

In this case, all tables will be inferred correctly, and you'll have complete information about your schema
</Callout>

## ---

### Performance

When working with relations in Drizzle ORM, especially in applications with 
significant data or complex queries, optimizing database performance is crucial.  
Indexes play a vital role in speeding up data retrieval, particularly when querying 
related data. This section outlines recommended indexing strategies for each type 
of relationship defined using Drizzle ORM.

##### One-to-one Relationships

In a one-to-one relationship, like the "user invites user" example or the
"user has profile info" example, the key performance consideration is efficient joining 
of the related tables.

<Callout>
For optimal performance in one-to-one relationships, you should create an index 
on the foreign key column in the table that is being referenced 
(the "target" table in the relation).
</Callout>

<Callout collapsed='Why it is important'>
When you query data with related one-to-one information, Drizzle performs a JOIN operation. An index on the foreign key column allows the database to quickly 
locate the related row in the target table, significantly speeding up the join process.
</Callout>

**Example:**
```typescript
import * as p from 'drizzle-orm/mysql-core';
import { defineRelations } from 'drizzle-orm';

export const users = p.mysqlTable('users', {
	id: p.int().autoincrement().primaryKey(),
	name: p.text(),
});

export const profileInfo = p.mysqlTable('profile_info', {
	id: p.int().autoincrement().primaryKey(),
	userId: p.int('user_id').references(() => users.id),
	metadata: p.json(),
});

export const relations = defineRelations({ users, profileInfo }, (r) => ({
	users: {
		profileInfo: r.one.profileInfo({
			from: r.users.id,
			to: r.profileInfo.userId,
		})
	}
}));
```

To optimize queries fetching user data along with their profile information, 
you should create an index on the `userId` column in the `profile_info` table.

```typescript {13-15}
import * as p from 'drizzle-orm/mysql-core';
import { defineRelations } from 'drizzle-orm';

export const users = p.mysqlTable('users', {
	id: p.int().autoincrement().primaryKey(),
	name: p.text(),
});

export const profileInfo = p.mysqlTable('profile_info', {
	id: p.int().autoincrement().primaryKey(),
	userId: p.int('user_id').references(() => users.id),
	metadata: p.json(),
}, (table) => [
  p.index('profile_info_user_id_idx').on(table.userId)
]);

export const relations = defineRelations({ users, profileInfo }, (r) => ({
	users: {
		profileInfo: r.one.profileInfo({
			from: r.users.id,
			to: r.profileInfo.userId,
		})
	}
}));
```
```sql
CREATE INDEX `profile_info_user_id_idx` ON `profile_info` (`user_id`);
```

#### One-to-many Relationships

Similar to one-to-one relationships, one-to-many relations benefit significantly 
from indexing to optimize join operations. Consider the "users and posts" example where one user can have many posts.

<Callout>
For one-to-many relationships, create an index on the foreign key column in the table that represents the "many" side of the relationship (the table with the foreign key referencing the "one" side).
</Callout>

<Callout collapsed='Why it is important'>
When you fetch a user with their posts or posts with their authors, joins are performed.
Indexing the foreign key (`authorId` in `posts` table) allows the database to efficiently 
retrieve all posts associated with a given user or quickly find the author of a post.
</Callout>

**Example:**
```typescript
import * as p from "drizzle-orm/mysql-core";
import { defineRelations } from 'drizzle-orm';

export const users = p.mysqlTable('users', {
	id: p.int().autoincrement().primaryKey(),
	name: p.text(),
});

export const posts = p.mysqlTable('posts', {
	id: p.int().autoincrement().primaryKey(),
	content: p.text(),
	authorId: p.int('author_id'),
});

export const relations = defineRelations({ users, posts }, (r) => ({
  posts: {
    author: r.one.users({
      from: r.posts.authorId,
      to: r.users.id,
    }),
  },
  users: {
    posts: r.many.posts(),
  },
}));
```

To optimize queries involving users and their posts, create an index on the `authorId` column in the `posts` table.

```typescript {13-15}
import * as p from "drizzle-orm/mysql-core";
import { defineRelations } from 'drizzle-orm';

export const users = p.mysqlTable('users', {
	id: p.int().autoincrement().primaryKey(),
	name: p.text(),
});

export const posts = p.mysqlTable('posts', {
	id: p.int().autoincrement().primaryKey(),
	content: p.text(),
	authorId: p.int('author_id'),
}, (t) => [
  p.index('posts_author_id_idx').on(t.authorId)
]);

export const relations = defineRelations({ users, posts }, (r) => ({
  posts: {
    author: r.one.users({
      from: r.posts.authorId,
      to: r.users.id,
    }),
  },
  users: {
    posts: r.many.posts(),
  },
}));
```
```sql
CREATE INDEX `posts_author_id_idx` ON `posts` (`author_id`);
```

#### Many-to-many Relationships

Many-to-many relationships, implemented using junction tables, require a slightly 
more nuanced indexing strategy to ensure optimal query performance. 
Consider the "users and groups" example with the `usersToGroups` junction table.

<Callout>
For many-to-many relationships, it is generally recommended to create the following 
indexes on the junction table:
1.  **Index on each foreign key column individually:** This optimizes queries that 
filter or join based on a single side of the relationship 
(e.g., finding all groups for a user OR all users in a group).
2.  **Composite index on both foreign key columns together:** This is crucial for 
efficiently resolving the many-to-many relationship itself. It speeds up queries that need to find the connections between both entities.
</Callout>

<Callout collapsed='Why it is important'>
When querying many-to-many relations, especially when using `through` in Drizzle ORM, the database needs to efficiently navigate the junction table.

- Indexes on individual foreign key columns (`userId`, `groupId` in `usersToGroups`) help when you are querying from one side to find the other (e.g., "find groups for a user").
- The composite index on `(userId, groupId)` in `usersToGroups` is particularly important for quickly finding all relationships defined in the junction table. This is used when Drizzle ORM resolves the `many-to-many` relation to fetch related entities.
</Callout>

**Example:**

In the "users and groups" example, the `usersToGroups` junction table connects `users` and `groups`.

```typescript
import { defineRelations } from 'drizzle-orm';
import * as p from 'drizzle-orm/mysql-core';

export const users = p.mysqlTable('users', {
  id: p.int().autoincrement().primaryKey(),
  name: p.text(),
});

export const groups = p.mysqlTable('groups', {
  id: p.int().autoincrement().primaryKey(),
  name: p.text(),
});

export const usersToGroups = p.mysqlTable(
  'users_to_groups',
  {
    userId: p.int('user_id')
      .notNull()
      .references(() => users.id),
    groupId: p.int('group_id')
      .notNull()
      .references(() => groups.id),
  },
  (t) => [p.primaryKey({ columns: [t.userId, t.groupId] })],
);

export const relations = defineRelations({ users, groups, usersToGroups },
  (r) => ({
    users: {
      groups: r.many.groups({
        from: r.users.id.through(r.usersToGroups.userId),
        to: r.groups.id.through(r.usersToGroups.groupId),
      }),
    },
    groups: {
      participants: r.many.users(),
    },
  })
);
```

To optimize queries for users and groups, create indexes on `usersToGroups` table as follows:

```typescript {26-28}
import { defineRelations } from 'drizzle-orm';
import * as p from 'drizzle-orm/mysql-core';

export const users = p.mysqlTable('users', {
  id: p.int().autoincrement().primaryKey(),
  name: p.text(),
});

export const groups = p.mysqlTable('groups', {
  id: p.int().autoincrement().primaryKey(),
  name: p.text(),
});

export const usersToGroups = p.mysqlTable(
  'users_to_groups',
  {
    userId: p.int('user_id')
      .notNull()
      .references(() => users.id),
    groupId: p.int('group_id')
      .notNull()
      .references(() => groups.id),
  },
  (t) => [
    p.primaryKey({ columns: [t.userId, t.groupId] }),
    p.index('users_to_groups_user_id_idx').on(t.userId),
    p.index('users_to_groups_group_id_idx').on(t.groupId),
    p.index('users_to_groups_composite_idx').on(t.userId, t.groupId),
  ],
);

export const relations = defineRelations({ users, groups, usersToGroups },
  (r) => ({
    users: {
      groups: r.many.groups({
        from: r.users.id.through(r.usersToGroups.userId),
        to: r.groups.id.through(r.usersToGroups.groupId),
      }),
    },
    groups: {
      participants: r.many.users(),
    },
  })
);
```
```sql
CREATE INDEX `users_to_groups_user_id_idx` ON `users_to_groups` (`user_id`);
CREATE INDEX `users_to_groups_group_id_idx` ON `users_to_groups` (`group_id`);
CREATE INDEX `users_to_groups_composite_idx` ON `users_to_groups` (`user_id`,`group_id`);
```

By applying these indexing strategies, you can significantly improve the performance of your Drizzle ORM applications when working with relational data, especially as your data volume grows and your queries become more complex. Remember to choose the indexes that best suit your specific query patterns and application needs.

## ---

### Foreign keys

You might've noticed that `relations` look similar to foreign keys — they even have a `references` property. So what's the difference?

While foreign keys serve a similar purpose, defining relations between tables, they work on a different level compared to `relations`.

Foreign keys are a database level constraint, they are checked on every `insert`/`update`/`delete` operation and throw an error if a constraint is violated.
On the other hand, `relations` are a higher level abstraction, they are used to define relations between tables on the application level only.
They do not affect the database schema in any way and do not create foreign keys implicitly.

What this means is `relations` and foreign keys can be used together, but they are not dependent on each other.
You can define `relations` without using foreign keys (and vice versa), which allows them to be used with databases that do not support foreign keys.

The following two examples will work exactly the same in terms of querying the data using Drizzle relational queries.

<CodeTabs items={["schema1.ts", "schema2.ts"]}>
<CodeTab>
```ts {15}
export const users = p.mysqlTable("users", {
  id: p.int().autoincrement().primaryKey(),
  name: p.text(),
});

export const profileInfo = p.mysqlTable("profile_info", {
  id: p.int().autoincrement().primaryKey(),
  userId: p.int("user_id"),
  metadata: p.json(),
});

export const relations = defineRelations({ users, profileInfo }, (r) => ({
  users: {
    profileInfo: r.one.profileInfo({
      from: r.users.id,
      to: r.profileInfo.userId,
    }),
  },
}));
```
</CodeTab>
<CodeTab>
```ts {15}
export const users = p.mysqlTable("users", {
  id: p.int().autoincrement().primaryKey(),
  name: p.text(),
});

export const profileInfo = p.mysqlTable("profile_info", {
  id: p.int().autoincrement().primaryKey(),
  userId: p.int("user_id").references(() => users.id),
  metadata: p.json(),
});

export const relations = defineRelations({ users, profileInfo }, (r) => ({
  users: {
    profileInfo: r.one.profileInfo({
      from: r.users.id,
      to: r.profileInfo.userId,
    }),
  },
}));
```
</CodeTab>
</CodeTabs>

### Disambiguating relations

Drizzle also provides the `alias` option as a way to disambiguate
relations when you define multiple of them between the same two tables. For
example, if you define a `posts` table that has the `author` and `reviewer`
relations.

```ts {19,22,29,34}
import { mysqlTable, int, text } from 'drizzle-orm/mysql-core';
import { defineRelations } from 'drizzle-orm';
 
export const users = mysqlTable('users', {
	id: int().primaryKey(),
	name: text(),
});

export const posts = mysqlTable('posts', {
	id: int().primaryKey(),
	content: text(),
	authorId: int('author_id'),
	reviewerId: int('reviewer_id'),
});
 
export const relations = defineRelations({ users, posts }, (r) => ({
  users: {
    posts: r.many.posts({
      alias: "author",
    }),
    reviewedPosts: r.many.posts({
      alias: "reviewer",
    }),
  },
  posts: {
    author: r.one.users({
      from: r.posts.authorId,
      to: r.users.id,
      alias: "author",
    }),
    reviewer: r.one.users({
      from: r.posts.authorId,
      to: r.users.id,
      alias: "reviewer",
    }),
  },
}));
```


Source: https://orm.drizzle.team/docs/mysql/rqb

import Npm from '@mdx/Npm.astro';
import Callout from '@mdx/Callout.astro';
import CodeTabs from '@mdx/CodeTabs.astro';
import CodeTab from '@mdx/CodeTab.astro';
import Section from '@mdx/Section.astro';

# Drizzle Queries

Drizzle ORM is designed to be a thin typed layer on top of SQL. 
We truly believe we've designed the best way to operate an SQL database from TypeScript and it's time to make it better.  
  
Relational queries are meant to provide you with a great developer experience for querying 
nested relational data from an SQL database, avoiding multiple joins and complex data mappings.  

It is an extension to the existing schema definition and query builder. 
You can opt-in to use it based on your needs. 
We've made sure you have both the best-in-class developer experience and performance.  

<Callout type="info" title='Important'>
Inside relational queries, references to a table's columns must go through the callback parameter, not through the imported table object. 
This applies to every clause that accepts a callback — `orderBy`, `where`.`RAW`, `extras` and `subqueries inside extras`. 
The callback exposes the aliased table for the current query scope, which is required for correct SQL generation in nested or self-referential queries.

<Callout type="error" title='❌' collapsed="Example">
```ts
await db.query.posts.findMany({
  orderBy: sql`${posts.id} asc`, // <- ❌ direct table usage
  with: {
    comments: {
      orderBy: sql`${comments.id} desc`, // <- ❌ direct table usage
    },
  },
});
```
```ts
await db.query.users.findMany({
  where: {
    RAW: sql`${users.name} LIKE 'john%'`, // <- ❌ direct table usage
  },
});
```
```ts
await db.query.users.findMany({
  extras: {
    loweredName: sql<string>`lower(${users.name})`, // <- ❌ direct table usage
    totalPostsCount: db.$count(posts, eq(posts.authorId, users.id)),  // <- ❌ direct table usage
  },
});
```
</Callout>
<Callout type="default" title='✅' collapsed="Example">
```ts
await db.query.posts.findMany({
  orderBy: (t) => sql`${t.id} asc`, // <- ✅ callback used
  with: {
    comments: {
      orderBy: (t, { desc }) => desc(t.id), // <- ✅ callback used
    },
  },
});
```
```ts
await db.query.users.findMany({
  where: {
    RAW: (t) => sql`${t.name} LIKE 'john%'`, // <- ✅ callback used
  },
});
```
```ts
await db.query.users.findMany({
  extras: {
    loweredName: (t, { sql }) => sql<string>`lower(${t.name})`, // <- ✅ callback used
    totalPostsCount: (t) => db.$count(posts, eq(posts.authorId, t.id)), // <- ✅ callback used
  },
});
```
</Callout>
</Callout>

<br/>

<CodeTabs items={["index.ts", "schema.ts", "relations.ts"]}>
	<CodeTab>
	```typescript copy
	import { drizzle } from "drizzle-orm/mysql2";
	import { relations } from "./relations";

	const db = drizzle(process.env.DATABASE_URL, { relations });

	const result = await db.query.users.findMany({
	  with: {
	    posts: true,
	  },
	});
	```

	```ts
	[{
		id: 10,
		name: "Dan",
		posts: [
			{
				id: 1,
				content: "SQL is awesome",
				authorId: 10,
			},
			{
				id: 2,
				content: "But check relational queries",
				authorId: 10,
			}
		]
	}]
	```
	</CodeTab>

	```typescript copy
    import * as p from "drizzle-orm/mysql-core";
    
    export const posts = p.mysqlTable("posts", {
      id: p.int().primaryKey().autoincrement(),
      content: p.text().notNull(),
      authorId: p.int("author_id").notNull(),
    });
    
    export const users = p.mysqlTable("users", {
      id: p.int().primaryKey().autoincrement(),
      name: p.text().notNull(),
    });
	```

	```typescript copy
	import { defineRelations } from "drizzle-orm";
	import { posts, users } from "./schema";

	export const relations = defineRelations({ users, posts }, (r) => ({
      posts: {
        author: r.one.users({
          from: r.posts.authorId,
          to: r.users.id,
        }),
      },
      users: {
        posts: r.many.posts(),
      },
    }));
	```
</CodeTabs>

Relational queries are an extension to Drizzle's original **[query builder](/docs/mysql/select)**.
You need to provide all `tables` and `relations` from your schema file/files upon `drizzle()` 
initialization and then just use the `db.query` API.

<CodeTabs items={["index.ts", "schema.ts", "relations.ts"]}>
<CodeTab>
```ts
import { relations } from './relations';
import { drizzle } from 'drizzle-orm/mysql2';

const db = drizzle(process.env.DATABASE_URL, { relations });

await db.query.users.findMany(...);
```
</CodeTab>
```typescript copy
import { type AnyMySqlColumn, int, mysqlTable, primaryKey, text, timestamp } from 'drizzle-orm/mysql-core';

export const users = mysqlTable('users', {
	id: int().primaryKey().autoincrement(),
	name: text().notNull(),
	invitedBy: int('invited_by').references((): AnyMySqlColumn => users.id),
});

export const groups = mysqlTable('groups', {
	id: int().primaryKey().autoincrement(),
	name: text().notNull(),
	description: text(),
});

export const usersToGroups = mysqlTable('users_to_groups', {
	id: int().primaryKey().autoincrement(),
	userId: int('user_id').notNull().references(() => users.id),
	groupId: int('group_id').notNull().references(() => groups.id),
}, (t) => [
	primaryKey({ columns: [t.userId, t.groupId] })
]);

export const posts = mysqlTable('posts', {
	id: int().primaryKey().autoincrement(),
	content: text().notNull(),
	authorId: int('author_id').references(() => users.id),
	createdAt: timestamp('created_at').notNull().defaultNow(),
});

export const comments = mysqlTable('comments', {
	id: int().primaryKey().autoincrement(),
	content: text().notNull(),
	creator: int().references(() => users.id),
	postId: int('post_id').references(() => posts.id),
	createdAt: timestamp('created_at').notNull().defaultNow(),
});

export const commentLikes = mysqlTable('comment_likes', {
	id: int().primaryKey().autoincrement(),
	creator: int().references(() => users.id),
	commentId: int('comment_id').references(() => comments.id),
	createdAt: timestamp('created_at').notNull().defaultNow(),
});
```
```typescript copy
import { defineRelations } from 'drizzle-orm';
import * as schema from './schema';

export const relations = defineRelations(schema, (r) => ({
    users: {
      invitee: r.one.users({
        from: r.users.invitedBy,
        to: r.users.id,
      }),
      groups: r.many.groups({
        from: r.users.id.through(r.usersToGroups.userId),
        to: r.groups.id.through(r.usersToGroups.groupId),
      }),
      posts: r.many.posts(),
    },
    groups: {
      users: r.many.users(),
    },
    posts: {
      author: r.one.users({
        from: r.posts.authorId,
        to: r.users.id,
      }),
      comments: r.many.comments(),
    },
    comments: {
      post: r.one.posts({
        from: r.comments.postId,
        to: r.posts.id,
      }),
      author: r.one.users({
        from: r.comments.creator,
        to: r.users.id,
      }),
      likes: r.many.commentLikes(),
    },
    commentLikes: {
      comment: r.one.comments({
        from: r.commentLikes.commentId,
        to: r.comments.id,
      }),
      author: r.one.users({
        from: r.commentLikes.creator,
        to: r.users.id,
      }),
    },
  })
);
```
</CodeTabs>

Drizzle provides `.findMany()` and `.findFirst()` APIs.
### Find many
<Section>
```typescript copy
const users = await db.query.users.findMany();
```
```ts
// result type
const result: {
	id: number;
	name: string;
	verified: boolean;
	invitedBy: number | null;
}[];
```
</Section>

### Find first
<Callout>
  `.findFirst()` will add `limit 1` to the query.
</Callout>
<Section>
```typescript copy
const user = await db.query.users.findFirst();
```
```ts
// result type
const result: {
	id: number;
	name: string;
	verified: boolean;
	invitedBy: number | null;
};
```
</Section>

### Include relations

`With` operator lets you combine data from multiple related tables and properly aggregate results.

**Getting all posts with comments:**
```typescript copy
const posts = await db.query.posts.findMany({
	with: {
		comments: true,
	},
});
```

**Getting first post with comments:**
```typescript copy
const post = await db.query.posts.findFirst({
	with: {
		comments: true,
	},
});
```

You can chain nested with statements as much as necessary.  
For any nested `with` queries Drizzle will infer types using [Core Type API](/docs/mysql/goodies#type-api).
  
**Get all users with posts. Each post should contain a list of comments:**
```typescript copy
const users = await db.query.users.findMany({
	with: {
		posts: {
			with: {
				comments: true,
			},
		},
	},
});
```

### Partial fields select
`columns` parameter lets you include or omit columns you want to get from the database.

<Callout type="info" emoji="ℹ️">
  Drizzle performs partial selects on the query level, no additional data is transferred from the database.

  Keep in mind that **a single SQL statement is outputted by Drizzle.**
</Callout>

**Get all posts with just `id`, `content` and include `comments`:**
```typescript copy
const posts = await db.query.posts.findMany({
	columns: {
		id: true,
		content: true,
	},
	with: {
		comments: true,
	}
});
```

**Get all posts without `content`:**
```typescript copy
const posts = await db.query.posts.findMany({
	columns: {
		content: false,
	},
});
```

<Callout type="info" emoji="ℹ️">
When both `true` and `false` select options are present, all `false` options are ignored.
</Callout>

If you include the `name` field and exclude the `id` field, `id` exclusion will be redundant, 
all fields apart from `name` would be excluded anyways.  
  
**Exclude and Include fields in the same query:**
<Section>
```typescript copy
const users = await db.query.users.findMany({
	columns: {
		name: true,
		id: false //ignored
	},
});
```
```ts
// result type
const users: {
	name: string;
};
```
</Section>

**Only include columns from nested relations:**
<Section>
```typescript copy
const res = await db.query.users.findMany({
	columns: {},
	with: {
		posts: true
	}
});
```
```ts
// result type
const res: {
	posts: {
		id: number,
		text: string
	}
}[];
```
</Section>

### Nested partial fields select
Just like with **[`partial select`](#partial-select)**, you can include or exclude columns of nested relations:
```typescript copy
const posts = await db.query.posts.findMany({
	columns: {
		id: true,
		content: true,
	},
	with: {
		comments: {
			columns: {
				authorId: false
			}
		}
	}
});
```

### Select filters
Just like in our SQL-like query builder, 
relational queries API lets you define filters and conditions with the list of our **[`operators`](/docs/mysql/operators)**.  

You can either import them from `drizzle-orm` or use from the callback syntax:
<Section>
```typescript copy
const users = await db.query.users.findMany({
	where: {
		id: 1
	}
});
```
```sql {6}
select 
	`d0`.`id` as `id`, 
	`d0`.`name` as `name` 
from `users` as `d0` 
where 
	`d0`.`id` = 1
```
</Section>

Find post with `id=1` and comments that were created before particular date:
```typescript copy
await db.query.posts.findMany({
  where: {
    id: 1,
  },
  with: {
    comments: {
      where: {
        createdAt: { lt: new Date() },
      },
    },
  },
});
```

**List of all filter operators**
```ts
where: {
    OR: [],
    AND: [],
    NOT: {},
    RAW: (table) => sql`${table.id} = 1`,

    // filter by relations
    [relation]: {},

	  // filter by columns
    [column]: {
      OR: [],
      AND: [],
      NOT: {},
      eq: 1,
      ne: 1,
      gt: 1,
      gte: 1,
      lt: 1,
      lte: 1,
      in: [1],
      notIn: [1],
      like: "",
      notLike: "",
      isNull: true,
      isNotNull: true
    },
},
```

**Examples**
<CodeTabs items={["simple eq", "using AND", "using OR", "using NOT", "complex example using RAW"]}>
<CodeTab>
```ts
const response = await db.query.users.findMany({
  where: {
    age: 15,
  },
});
```
```sql {8}
SELECT
	`d0`.`id` AS `id`,
	`d0`.`name` AS `name`,
	`d0`.`age` AS `age`
FROM
	`users` AS `d0`
WHERE
	`d0`.`age` = 15;
```
</CodeTab>
<CodeTab>
```ts
const response = await db.query.users.findMany({
  where: {
    age: 15,
    name: 'John'
  },
});
```
```sql {9-10}
SELECT
	`d0`.`id` AS `id`,
	`d0`.`name` AS `name`,
	`d0`.`age` AS `age`
FROM
	`users` AS `d0`
WHERE
	(
		(`d0`.`age` = 15)
		AND (`d0`.`name` = 'John')
	);
```
</CodeTab>
<CodeTab>
```ts
const response = await db.query.users.findMany({
  where: {
    OR: [
      {
        id: {
          gt: 10,
        },
      },
      {
        name: {
          like: "John%",
        },
      },
    ],
  },
});
```
```sql {9-10}
SELECT
	`d0`.`id` AS `id`,
	`d0`.`name` AS `name`,
	`d0`.`age` AS `age`
FROM
	`users` AS `d0`
WHERE
	(
		(`d0`.`id` > 10)
		OR (`d0`.`name` LIKE 'John%')
	);
```
</CodeTab>
<CodeTab>
```ts
const response = await db.query.users.findMany({
  where: {
    NOT: {
      id: {
        gt: 10,
      },
    },
    name: {
      like: "John%",
    },
  },
});
```
```sql {9-10}
SELECT
	`d0`.`id` AS `id`,
	`d0`.`name` AS `name`,
	`d0`.`age` AS `age`
FROM
	`users` AS `d0`
WHERE
	(
		(not(`d0`.`id` > 10))
		AND (`d0`.`name` LIKE 'John%')
	);
```
</CodeTab>
<CodeTab>
```ts
// schema.ts
import { int, json, mysqlTable, text, timestamp } from "drizzle-orm/mysql-core";
import { sql } from "drizzle-orm";

export const users = mysqlTable("users", {
  id: int().primaryKey(),
  name: text(),
  email: text().notNull(),
  age: int(),
  createdAt: timestamp("created_at").defaultNow(),
  lastLogin: timestamp("last_login"),
  subscriptionEnd: timestamp("subscription_end"),
  lastActivity: timestamp("last_activity"),
  preferences: json(), // JSON column for user settings/preferences
  interests: json().$type<string[]>(), // Array column for user interests
});
```
```ts
const response = await db.query.users.findMany({
    where: {
      AND: [
        {
          OR: [{ RAW: (table) => sql`${table.name} LIKE 'john%'` }, { name: { like: "jane%" } }],
        },
        { 
			RAW: (table) => sql`${table.age} BETWEEN 25 AND 35` 
		},
      ],
    },
  }),
```
```sql
SELECT
	`d0`.`id` AS `id`,
	`d0`.`name` AS `name`,
	`d0`.`email` AS `email`,
	`d0`.`age` AS `age`,
	`d0`.`created_at` AS `createdAt`,
	`d0`.`last_login` AS `lastLogin`,
	`d0`.`subscription_end` AS `subscriptionEnd`,
	`d0`.`last_activity` AS `lastActivity`,
	`d0`.`preferences` AS `preferences`,
	`d0`.`interests` AS `interests`
FROM
	`users` AS `d0`
WHERE
	(
		(
			(
				(`d0`.`name` LIKE 'john%')
				OR (`d0`.`name` LIKE 'jane%')
			)
		)
		AND (`d0`.`age` BETWEEN 25 AND 35)
	);
```
</CodeTab>
</CodeTabs>

### Relations Filters

With Drizzle Relations, you can filter not only by the table you're querying but also by any table you include in the query.

**Example:** Get all `users` whose ID>10 and who have at least one post with content starting with "M"
```ts
const usersWithPosts = await db.query.usersTable.findMany({
  where: {
    id: {
      gt: 10
    },
    posts: {
      content: {
        like: 'M%'
      }
    }
  },
});
```

**Example:** Get all `users` with posts, only if user has at least 1 post
```ts
const response = await db.query.users.findMany({
  with: {
    posts: true,
  },
  where: {
    posts: true,
  },
});
```

### Limit & Offset
Drizzle ORM provides `limit` & `offset` API for queries and for the nested entities.
  
**Find 5 posts:**
```typescript copy
await db.query.posts.findMany({
	limit: 5,
});
```

**Find posts and get 3 comments at most:**
```typescript copy
await db.query.posts.findMany({
	with: {
		comments: {
			limit: 3,
		},
	},
});
```

<Callout type="warning" emoji="⚠️">
  `offset` now can be used in with tables as well!
</Callout>
```typescript 
await db.query.posts.findMany({
	limit: 5,
	offset: 2, // correct ✅
	with: {
		comments: {
			offset: 3, // correct ✅
			limit: 3,
		},
	},
});
```

Find posts with comments from the 6th to the 10th post:
```typescript copy
await db.query.posts.findMany({
	with: {
		comments: true,
	},
  limit: 5,
  offset: 5,
});
```

### Order By
Drizzle provides API for ordering in the relational query builder.  

You can use same ordering **[core API](/docs/mysql/select#order-by)** or use
`order by` operator from the callback with no imports.  

<Callout title='important'>
When you use multiple `orderBy` statements in the same table, they will be included in the query in the same order in which you added them
</Callout>

<Section>
```typescript copy
await db.query.posts.findMany({
  orderBy: {
    id: "asc",
  },
});
```
</Section>

**Order by `asc` + `desc`:**
```typescript copy
  await db.query.posts.findMany({
    orderBy: { id: "asc" },
    with: {
      comments: {
        orderBy: { id: "desc" },
      },
    },
  });
```

You can also use custom `sql` in order by statement:

```typescript copy
await db.query.posts.findMany({
  orderBy: (t) => sql`${t.id} asc`,
  with: {
    comments: {
      orderBy: (t, { desc }) => desc(t.id),
    },
  },
});
```

### Include custom fields
Relational query API lets you add custom additional fields. 
It's useful when you need to retrieve data and apply additional functions to it.
<Callout type="warning" emoji="⚠️">
	As of now aggregations are not supported in `extras`, please use **[`core queries`](/docs/mysql/select)** for that.
</Callout>

<Section>
```typescript copy {5}
import { sql } from 'drizzle-orm';

await db.query.users.findMany({
  extras: {
    loweredName: (table) => sql`lower(${table.name})`,
  },
});
```
```typescript copy {3}
await db.query.users.findMany({
	extras: {
		loweredName: (users, { sql }) => sql`lower(${users.name})`,
	},
})
```
</Section>

`lowerName` as a key will be included to all fields in returned object.

<Callout type="warning" emoji="⚠️">
  If you will specify `.as("<alias>")` for any extras field - drizzle will ignore it
</Callout>

To retrieve all users with groups, but with the fullName field included (which is a concatenation of firstName and lastName), 
you can use the following query with the Drizzle relational query builder.

<Section>
```typescript copy
const res = await db.query.users.findMany({
	extras: {
		fullName: (users, { sql }) => sql<string>`concat(${users.name}, " ", ${users.name})`,
	},
	with: {
		groups: true,
	},
});
```
```ts
// result type
const res: {
    id: number;
    name: string;
    age: number | null;
    invitedBy: number | null;
    fullName: string;
    groups: {
        id: number;
        name: string;
        description: string | null;
    }[];
}[]
```
</Section>

To retrieve all posts with comments and add an additional field to calculate the size of the post content and the size of each comment content:
<Section>
```typescript copy
const res = await db.query.posts.findMany({
	extras: {
		contentLength: (table, { sql }) => sql<number>`char_length(${table.content})`,
	},
	with: {
		comments: {
			extras: {
				commentSize: (table, { sql }) => sql<number>`char_length(${table.content})`,
			},
		},
	},
});
```
```ts
// result type
const res: {
    id: number;
    createdAt: Date;
    content: string;
    authorId: number | null;
    contentLength: number;
    comments: {
        id: number;
        createdAt: Date;
        content: string;
        creator: number | null;
        postId: number | null;
        commentSize: number;
    }[];
}[]
```
</Section>

### Include subqueries

You can also use subqueries within Relational Queries to leverage the power of custom SQL syntax

**Get users with posts and total posts count for each user**
```ts
import { posts } from './schema';
import { eq } from 'drizzle-orm';

await db.query.users.findMany({
  with: {
    posts: true
  },
  extras: {
    totalPostsCount: (table) => db.$count(posts, eq(posts.authorId, table.id)),
  }
});
```
```sql
SELECT
	`d0`.`id` AS `id`,
	`d0`.`name` AS `name`,
	`d0`.`age` AS `age`,
	(
		(
			SELECT
				count(*)
			FROM
				`posts`
			WHERE
				`posts`.`author_id` = `d0`.`id`
		)
	) AS `totalPostsCount`,
	`posts`.`r` AS `posts`
FROM
	`users` AS `d0`
	LEFT JOIN LATERAL (
		SELECT
			coalesce(json_arrayagg(json_object('id', `id`, 'name', `name`, 'authorId', `authorId`)), json_array()) AS `r`
		FROM
			(
				SELECT
					`d1`.`id` AS `id`,
					`d1`.`name` AS `name`,
					`d1`.`author_id` AS `authorId`
				FROM
					`posts` AS `d1`
				WHERE
					`d0`.`id` = `d1`.`author_id`
			) AS `t`
	) AS `posts` ON TRUE;
```

### Prepared statements
Prepared statements are designed to massively improve query performance — [see here.](/docs/mysql/perf-queries)

In this section, you can learn how to define placeholders and execute prepared statements 
using the Drizzle relational query builder.

##### **Placeholder in `where`**

<Section>
```ts copy
const prepared = db.query.users.findMany({
    where: { id: { eq: sql.placeholder("id") } },
    with: {
      posts: {
        where: { id: 1 },
      },
    },
}).prepare();

const usersWithPosts = await prepared.execute({ id: 1 });
```
</Section>

##### **Placeholder in `limit`**

<Section>
```ts copy
const prepared = db.query.users.findMany({
    with: {
      posts: {
        limit: sql.placeholder("limit"),
      },
    },
  }).prepare();

const usersWithPosts = await prepared.execute({ limit: 1 });
```
</Section>

##### **Placeholder in `offset`**

<Section>
```ts copy
const prepared = db.query.users.findMany({
	offset: sql.placeholder('offset'),
	with: {
		posts: true,
	},
}).prepare();

const usersWithPosts = await prepared.execute({ offset: 1 });
```
</Section>

##### **Multiple placeholders**

<Section>
```ts copy
const prepared = db.query.users.findMany({
    limit: sql.placeholder("uLimit"),
    offset: sql.placeholder("uOffset"),
    where: {
      OR: [{ id: { eq: sql.placeholder("id") } }, { id: 3 }],
    },
    with: {
      posts: {
        where: { id: { eq: sql.placeholder("pid") } },
        limit: sql.placeholder("pLimit"),
      },
    },
}).prepare();

const usersWithPosts = await prepared.execute({ pLimit: 1, uLimit: 3, uOffset: 1, id: 2, pid: 6 });
```
</Section>


Source: https://orm.drizzle.team/docs/mysql/schemas

import Section from '@mdx/Section.astro';
import Callout from '@mdx/Callout.astro';

# Table schemas

If you declare an entity within a schema, query builder will prepend schema names in queries:<br/>
`select * from schema.users`

<Section>
    ```ts {3,5}
    import { int, text, mysqlSchema } from "drizzle-orm/mysql-core";

    export const mySchema = mysqlSchema("my_schema")

    export const mySchemaUsers = mySchema.table("users", {
      id: int("id").primaryKey().autoincrement(),
      name: text("name"),
    });
    ```
    </Section>

{/* TODO: ??? example > **Warning**
> If you will have tables with same names in different schemas then drizzle will respond with `never[]` error in result types and error from database
>
> In this case you may use [alias syntax](./joins#join-aliases-and-self-joins) */}


Source: https://orm.drizzle.team/docs/mysql/seed-functions

import Callout from '@mdx/Callout.astro';
import Tab from "@mdx/Tab.astro";
import Tabs from "@mdx/Tabs.astro";

# Generators

<Callout title='warning'>
For now, specifying `arraySize` along with `isUnique` in generators that support it will result in unique values being generated (not unique arrays), which will then be packed into arrays.
</Callout>

## ---

### `default`

<rem025 />
Generates the same given value each time the generator is called.

|  | param          | default     | type
|:-| :--------      | :--------   | :--------
|  |`defaultValue`  |--           |`any`
|  |`arraySize`     |--           |`number`

<rem025 />

```ts 
import { seed } from "drizzle-seed";

await seed(db, schema, { count: 1000 }).refine((funcs) => ({
  posts: {
    columns: {
      content: funcs.default({
        // value you want to generate
        defaultValue: "post content",

        // number of elements in each one-dimensional array. 
        // (If specified, arrays will be generated.)
        arraySize: 3
      }),
    },
  },
}));

```

### `valuesFromArray`

<rem025 />
Generates values from given array

|  | param      | default                     | type
|:-| :--------  | :--------                   | :--------
|  |`values`    |--                           |`any[]` \| `{ weight: number; values: any[] }[]`
|  |`isUnique`  |`database column uniqueness` |`boolean`
|  |`arraySize` |--                           |`number`


<rem025 />
```ts 
import { seed } from "drizzle-seed";

await seed(db, schema, { count: 1000 }).refine((funcs) => ({
  posts: {
    columns: {
      title: funcs.valuesFromArray({
        // Array of values you want to generate (can be an array of weighted values)
        values: ["Title1", "Title2", "Title3", "Title4", "Title5"],

        // Property that controls whether the generated values will be unique or not
        isUnique: true,
        
        // number of elements in each one-dimensional array. 
        // (If specified, arrays will be generated.)
        arraySize: 3
      }),
    },
  },
}));

```

### `intPrimaryKey`

<rem025 />
Generates sequential integers starting from 1.

|  | param      | default    | type
|:-| :--------  | :--------  | :--------
|  |--          |--          |--

<rem025 />

```ts 
import { seed } from "drizzle-seed";

await seed(db, schema, { count: 1000 }).refine((funcs) => ({
  posts: {
    columns: {
      id: funcs.intPrimaryKey(),
    },
  },
}));

```

### `number`

<rem025 />
Generates numbers with a floating point within the given range

|  | param      | default                                                                                               | type
|:-| :--------  | :--------                                                                                             | :--------
|  |`isUnique`  |`database column uniqueness`                                                                           |`boolean`
|  |`precision` |`100`                                                                                                  |`number`
|  |`maxValue`  |``` `precision * 1000` if isUnique equals false``` ``` `precision * count` if isUnique equals true```  |`number`
|  |`minValue`  |`-maxValue`                                                                                            |`number`
|  |`arraySize` |--                                                                                                     |`number`

<rem025 />
```ts 
import { seed } from "drizzle-seed";

await seed(db, schema, { count: 1000 }).refine((funcs) => ({
  products: {
    columns: {
      unitPrice: funcs.number({
        // lower border of range.
        minValue: 10,

        // upper border of range.
        maxValue: 120,
        
        // precision of generated number:
        // precision equals 10 means that values will be accurate to one tenth (1.2, 34.6);
        // precision equals 100 means that values will be accurate to one hundredth (1.23, 34.67).
        precision: 100,

        // property that controls if generated values gonna be unique or not.
        isUnique: false,

        // number of elements in each one-dimensional array. 
        // (If specified, arrays will be generated.)
        arraySize: 3
      }),
    },
  },
}));

```

### `int`

<rem025 />
Generates integers within the given range

|  | param      | default                                                                            | type
|:-| :--------  | :--------                                                                          | :--------
|  |`isUnique`  |`database column uniqueness`                                                        |`boolean`
|  |`maxValue`  |``` `1000` if isUnique equals false``` ``` `count * 10` if isUnique equals true```  |`number \| bigint`
|  |`minValue`  |`-maxValue`                                                                         |`number \| bigint`
|  |`arraySize` |--                                                                                  |`number`

<rem025 />
```ts 
import { seed } from "drizzle-seed";

await seed(db, schema, { count: 1000 }).refine((funcs) => ({
  products: {
    columns: {
      unitsInStock: funcs.int({
        // lower border of range.
        minValue: 0,

        // lower border of range.
        maxValue: 100,

        // property that controls if generated values gonna be unique or not.
        isUnique: false,

        // number of elements in each one-dimensional array. 
        // (If specified, arrays will be generated.)
        arraySize: 3
      }),
    },
  },
}));

```

### `boolean`

<rem025 />
Generates boolean values (true or false)

|  | param      | default    | type
|:-| :--------  | :--------  | :--------
|  |`arraySize` |--          |`number`

<rem025 />
```ts 
import { seed } from "drizzle-seed";

await seed(db, schema, { count: 1000 }).refine((funcs) => ({
  users: {
    columns: {
      isAvailable: funcs.boolean({
        // number of elements in each one-dimensional array. 
        // (If specified, arrays will be generated.)
        arraySize: 3
      }),
    },
  },
}));

```

### `date`

<rem025 />
Generates a date within the given range

|  | param      | default                                                                                                   | type
|:-| :--------  | :--------------                                                                                           | :--------
|  |`minDate`   |``` `'2024-05-08' - 4 years` - if maxDate is not set``` ``` `maxDate - 8 years`  - if maxDate is set ```   |`string \| Date`
|  |`maxDate`   |``` `'2024-05-08' + 4 years` - if minDate is not set``` ``` `minDate + 8 years`  - if minDate is set ```   |`string \| Date`
|  |`arraySize` |--                                                                                                         |`number`

<Callout type='warning'>
If only one of the parameters (`minDate` or `maxDate`) is provided, the unspecified parameter will be calculated by adding or subtracting 8 years to/from the specified one
</Callout>

<rem025 />
```ts 
import { seed } from "drizzle-seed";

await seed(db, schema, { count: 1000 }).refine((funcs) => ({
  users: {
    columns: {
      birthDate: funcs.date({
        // lower border of range.
        minDate: "1990-01-01",

        // upper border of range.
        maxDate: "2010-12-31",

        // number of elements in each one-dimensional array. 
        // (If specified, arrays will be generated.)
        arraySize: 3
      }),
    },
  },
}));

```

### `time`

<rem025 />
Generates time in 24-hour format

|  | param      | default             | type
|:-| :--------  | :--------           | :--------
|  |`min`       |`'00:00:00.000Z'`    |`string \| Date`
|  |`max`       |`'23:59:59.999Z'`    |`string \| Date`
|  |`arraySize` |--                   |`number`

<rem025 />
```ts 
import { seed } from "drizzle-seed";

await seed(db, schema, { count: 1000 }).refine((funcs) => ({
  users: {
    columns: {
      birthTime: funcs.time({
        // lower border of range.
        min: "11:12:13.141",

        // upper border of range.
        max: "15:16:17.181",

        // number of elements in each one-dimensional array. 
        // (If specified, arrays will be generated.)
        arraySize: 3
      }),
    },
  },
}));

```

### `timestamp`

<rem025 />
Generates timestamps

|  | param           | default                                                                                       | type
|:-| :--------       | :--------                                                                                     | :--------
|  |`min`            |``` `'2024-05-08' - 2 years` - if max is not set``` ``` `max - 4 years`  - if max is set ```   |`string \| Date`
|  |`max`            |``` `'2024-05-08' + 2 years` - if min is not set``` ``` `min + 4 years`  - if min is set ```   |`string \| Date`
|  |`arraySize`      |--                                                                                             |`number`

<rem025 />
```ts 
import { seed } from "drizzle-seed";

await seed(db, schema, { count: 1000 }).refine((funcs) => ({
  orders: {
    columns: {
      shippedDate: funcs.timestamp({
        // lower border of range.
        min: "2025-03-07T11:12:13.141",

        // upper border of range.
        max: "2025-03-08T15:16:17.181",

        // number of elements in each one-dimensional array. 
        // (If specified, arrays will be generated.)
        arraySize: 3
      }),
    },
  },
}));

```

### `datetime`

<rem025 />
Generates datetime objects

|  | param        | default                                                                                       | type
|:-| :--------    | :--------                                                                                     | :--------
|  |`min`         |``` `'2024-05-08' - 2 years` - if max is not set``` ``` `max - 4 years`  - if max is set ```   |`string \| Date`
|  |`max`         |``` `'2024-05-08' + 2 years` - if min is not set``` ``` `min + 4 years`  - if min is set ```   |`string \| Date`
|  |`arraySize`   |--                                                                                             |`number`
<rem025 />
```ts 
import { seed } from "drizzle-seed";

await seed(db, schema, { count: 1000 }).refine((funcs) => ({
  orders: {
    columns: {
      shippedDate: funcs.datetime({
        // lower border of range.
        min: "2025-03-07 13:12:13Z",
        
        // upper border of range.
        max: "2025-03-09 15:12:13Z",

        // number of elements in each one-dimensional array. 
        // (If specified, arrays will be generated.)
        arraySize: 3
      }),
    },
  },
}));

```

### `year`

<rem025 />
Generates years in `YYYY` format

|  | param      | default    | type
|:-| :--------  | :--------  | :--------
|  |`arraySize` |--          |`number`

<rem025 />
```ts 
import { seed } from "drizzle-seed";

await seed(db, schema, { count: 1000 }).refine((funcs) => ({
  users: {
    columns: {
      birthYear: funcs.year({
        // number of elements in each one-dimensional array. 
        // (If specified, arrays will be generated.)
        arraySize: 3
      }),
    },
  },
}));

```

### `json`

<rem025 />
Generates JSON objects with a fixed structure

```ts
{ email, name, isGraduated, hasJob, salary, startedWorking, visitedCountries}

// or

{ email, name, isGraduated, hasJob, visitedCountries }
```

> The JSON structure will be picked randomly

|  | param      | default    | type
|:-| :--------  | :--------  | :--------
|  |`arraySize` |--          |`number`

<rem025 />
```ts 
import { seed } from "drizzle-seed";

await seed(db, schema, { count: 1000 }).refine((funcs) => ({
  users: {
    columns: {
      metadata: funcs.json({
        // number of elements in each one-dimensional array. 
        // (If specified, arrays will be generated.)
        arraySize: 3
      }),
    },
  },
}));

```

### `interval`

<rem025 />
Generates time intervals.

Example of a generated value: `1 year 12 days 5 minutes`

|  | param      | default                     | type
|:-| :--------  | :--------                   | :--------
|  |`isUnique`  |`database column uniqueness` |`boolean`
|  |`arraySize` |--                           |`number`

<rem025 />
```ts 
import { seed } from "drizzle-seed";

await seed(db, schema, { count: 1000 }).refine((funcs) => ({
  users: {
    columns: {
      timeSpentOnWebsite: funcs.interval({
        // `isUnique` - property that controls whether the generated values will be unique or not
        isUnique: true,

        // number of elements in each one-dimensional array. 
        // (If specified, arrays will be generated.)
        arraySize: 3
      }),
    },
  },
}));

```

### `string`

<rem025 />
Generates random strings

|  | param      | default                     | type
|:-| :--------  | :--------                   | :--------
|  |`isUnique`  |`database column uniqueness` |`boolean`
|  |`arraySize` |--                           |`number`

<rem025 />
```ts 
import { seed } from "drizzle-seed";

await seed(db, schema, { count: 1000 }).refine((funcs) => ({
  users: {
    columns: {
      hashedPassword: funcs.string({
        // `isUnique` - property that controls whether the generated values will be unique or not
        isUnique: false,
        
        // number of elements in each one-dimensional array. 
        // (If specified, arrays will be generated.)
        arraySize: 3
      }),
    },
  },
}));

```

### `uuid`

<rem025 />
Generates v4 UUID strings

|  | param      | default    | type
|:-| :--------  | :--------  | :--------
|  |`arraySize` |--          |`number`

<rem025 />
```ts 
import { seed } from "drizzle-seed";
await seed(db, schema, { count: 1000 }).refine((funcs) => ({
  products: {
    columns: {
      id: funcs.uuid({
        // number of elements in each one-dimensional array. 
        // (If specified, arrays will be generated.)
        arraySize: 3
      }),
    },
  },
}));
```

### `firstName`

<rem025 />
Generates a person's first name

|  | param      | default                     | type
|:-| :--------  | :--------                   | :--------
|  |`isUnique`  |`database column uniqueness` |`boolean`
|  |`arraySize` |--                           |`number`

<rem025 />
```ts 
import { seed } from "drizzle-seed";

await seed(db, schema, { count: 1000 }).refine((funcs) => ({
  users: {
    columns: {
      firstName: funcs.firstName({
        // `isUnique` - property that controls whether the generated values will be unique or not
        isUnique: true,

        // number of elements in each one-dimensional array. 
        // (If specified, arrays will be generated.)
        arraySize: 3
      }),
    },
  },
}));

```

### `lastName`

<rem025 />
Generates a person's last name

|  | param      | default                     | type
|:-| :--------  | :--------                   | :--------
|  |`isUnique`  |`database column uniqueness` |`boolean`
|  |`arraySize` |--                           |`number`

<rem025 />
```ts 
import { seed } from "drizzle-seed";

await seed(db, schema, { count: 1000 }).refine((funcs) => ({
  users: {
    columns: {
      lastName: funcs.lastName({
        // `isUnique` - property that controls whether the generated values will be unique or not
        isUnique: false,
        
        // number of elements in each one-dimensional array. 
        // (If specified, arrays will be generated.)
        arraySize: 3
      }),
    },
  },
}));

```

### `fullName`

<rem025 />
Generates a person's full name

|  | param      | default                     | type
|:-| :--------  | :--------                   | :--------
|  |`isUnique`  |`database column uniqueness` |`boolean`
|  |`arraySize` |--                           |`number`

<rem025 />
```ts 
import { seed } from "drizzle-seed";

await seed(db, schema, { count: 1000 }).refine((funcs) => ({
  users: {
    columns: {
      fullName: funcs.fullName({
        // `isUnique` - property that controls whether the generated values will be unique or not
        isUnique: true,

        // number of elements in each one-dimensional array. 
        // (If specified, arrays will be generated.)
        arraySize: 3
      }),
    },
  },
}));

```

### `email`

<rem025 />
Generates unique email addresses

|  | param      | default    | type
|:-| :--------  | :--------  | :--------
|  |`arraySize` |--          |`number`

<rem025 />
```ts 
import { seed } from "drizzle-seed";

await seed(db, schema, { count: 1000 }).refine((funcs) => ({
  users: {
    columns: {
      email: funcs.email({
        // number of elements in each one-dimensional array. 
        // (If specified, arrays will be generated.)
        arraySize: 3
      }),
    },
  },
}));

```

### `phoneNumber`

<rem025 />
Generates unique phone numbers

|  | param                    | default                                         | type
|:-| :--------                | :--------                                       | :--------
|  |`template`                |--                                               |`string`
|  |`prefixes`                |[Used dataset for prefixes](https://github.com/OleksiiKH0240/drizzle-orm/blob/main/drizzle-seed/src/datasets/phonesInfo.ts)   |`string[]`
|  |`generatedDigitsNumbers`  | `7` - `if prefixes was defined`                 |`number \| number[]`
|  |`arraySize`               |--                                               |`number`

<rem025 />
```ts 
import { seed } from "drizzle-seed";

//generate phone number using template property
await seed(db, schema, { count: 1000 }).refine((funcs) => ({
  users: {
    columns: {
      phoneNumber: funcs.phoneNumber({ 
        // `template` - phone number template, where all '#' symbols will be substituted with generated digits.
        template: "+(380) ###-####",

        // number of elements in each one-dimensional array. 
        // (If specified, arrays will be generated.)
        arraySize: 3
      }),
    },
  },
}));

```
```ts 
import { seed } from "drizzle-seed";

//generate phone number using prefixes and generatedDigitsNumbers properties
await seed(db, schema, { count: 1000 }).refine((funcs) => ({
  users: {
    columns: {
      phoneNumber: funcs.phoneNumber({
        // `prefixes` - array of any string you want to be your phone number prefixes.(not compatible with `template` property)
        prefixes: ["+380 99", "+380 67"],

        // `generatedDigitsNumbers` - number of digits that will be added at the end of prefixes.(not compatible with `template` property)
        generatedDigitsNumbers: 7,

        // number of elements in each one-dimensional array. 
        // (If specified, arrays will be generated.)
        arraySize: 3
      }),
    },
  },
}));

```
```ts 
import { seed } from "drizzle-seed";

// generate phone number using prefixes and generatedDigitsNumbers properties but with different generatedDigitsNumbers for prefixes
await seed(db, schema, { count: 1000 }).refine((funcs) => ({
  users: {
    columns: {
      phoneNumber: funcs.phoneNumber({
        // `prefixes` - array of any string you want to be your phone number prefixes.(not compatible with `template` property)
        prefixes: ["+380 99", "+380 67", "+1"],

        // `generatedDigitsNumbers` - number of digits that will be added at the end of prefixes.(not compatible with `template` property)
        generatedDigitsNumbers: [7, 7, 10],

        // number of elements in each one-dimensional array. 
        // (If specified, arrays will be generated.)
        arraySize: 3
      }),
    },
  },
}));

```
### `country`

<rem025 />
Generates country's names

|  | param      | default                     | type
|:-| :--------  | :--------                   | :--------
|  |`isUnique`  |`database column uniqueness` |`boolean`
|  |`arraySize` |--                           |`number`

<rem025 />

```ts 
import { seed } from "drizzle-seed";

await seed(db, schema, { count: 1000 }).refine((funcs) => ({
  users: {
    columns: {
      country: funcs.country({
        // `isUnique` - property that controls whether the generated values will be unique or not
        isUnique: false,
        
        // number of elements in each one-dimensional array. 
        // (If specified, arrays will be generated.)
        arraySize: 3
      }),
    },
  },
}));

```

### `city`

<rem025 />
Generates city's names

|  | param      | default                     | type
|:-| :--------  | :--------                   | :--------
|  |`isUnique`  |`database column uniqueness` |`boolean`
|  |`arraySize` |--                           |`number`

<rem025 />

```ts 
import { seed } from "drizzle-seed";

await seed(db, schema, { count: 1000 }).refine((funcs) => ({
  users: {
    columns: {
      city: funcs.city({
        // `isUnique` - property that controls whether the generated values will be unique or not
        isUnique: false,

        // number of elements in each one-dimensional array. 
        // (If specified, arrays will be generated.)
        arraySize: 3
      }),
    },
  },
}));

```

### `streetAddress`

<rem025 />
Generates street address

|  | param      | default                     | type
|:-| :--------  | :--------                   | :--------
|  |`isUnique`  |`database column uniqueness` |`boolean`
|  |`arraySize` |--                           |`number`

<rem025 />

```ts 
import { seed } from "drizzle-seed";

await seed(db, schema, { count: 1000 }).refine((funcs) => ({
  users: {
    columns: {
      streetAddress: funcs.streetAddress({
        // `isUnique` - property that controls whether the generated values will be unique or not
        isUnique: false,
        
        // number of elements in each one-dimensional array. 
        // (If specified, arrays will be generated.)
        arraySize: 3 
      }),
    },
  },
}));

```

### `jobTitle`

<rem025 />
Generates job titles

|  | param      | default    | type
|:-| :--------  | :--------  | :--------
|  |`arraySize` |--          |`number`

<rem025 />

```ts 
import { seed } from "drizzle-seed";

await seed(db, schema, { count: 1000 }).refine((funcs) => ({
  users: {
    columns: {
      jobTitle: funcs.jobTitle({
        // number of elements in each one-dimensional array. 
        // (If specified, arrays will be generated.)
        arraySize: 3
      }),
    },
  },
}));

```

### `postcode`

<rem025 />
Generates postal codes

|  | param      | default                     | type
|:-| :--------  | :--------                   | :--------
|  |`isUnique`  |`database column uniqueness` |`boolean`
|  |`arraySize` |--                           |`number`

<rem025 />

```ts 
import { seed } from "drizzle-seed";

await seed(db, schema, { count: 1000 }).refine((funcs) => ({
  users: {
    columns: {
      postcode: funcs.postcode({
        // `isUnique` - property that controls whether the generated values will be unique or not
        isUnique: true,

        // number of elements in each one-dimensional array. 
        // (If specified, arrays will be generated.)
        arraySize: 3
      }),
    },
  },
}));

```

### `state`

<rem025 />
Generates US states

|  | param      | default    | type
|:-| :--------  | :--------  | :--------
|  |`arraySize` |--          |`number`

<rem025 />

```ts 
import { seed } from "drizzle-seed";

await seed(db, schema, { count: 1000 }).refine((funcs) => ({
  users: {
    columns: {
      state: funcs.state({
        // number of elements in each one-dimensional array. 
        // (If specified, arrays will be generated.)
        arraySize: 3
      }),
    },
  },
}));

```

### `companyName`

<rem025 />
Generates random company's names

|  | param      | default                     | type
|:-| :--------  | :--------                   | :--------
|  |`isUnique`  |`database column uniqueness` |`boolean`
|  |`arraySize` |--                           |`number`

<rem025 />

```ts 
import { seed } from "drizzle-seed";

await seed(db, schema, { count: 1000 }).refine((funcs) => ({
  users: {
    columns: {
      company: funcs.companyName({ 
        // `isUnique` - property that controls whether the generated values will be unique or not
        isUnique: true,

        // number of elements in each one-dimensional array. 
        // (If specified, arrays will be generated.)
        arraySize: 3
      }),
    },
  },
}));

```
### `loremIpsum`

<rem025 />
Generates `lorem ipsum` text sentences.

|  | param            | default    | type
|:-| :--------        | :--------  | :--------
|  |`sentencesCount`  | 1          |`number`
|  |`arraySize`       |--          |`number`

<rem025 />

```ts 
import { seed } from "drizzle-seed";

await seed(db, schema, { count: 1000 }).refine((funcs) => ({
  posts: {
    columns: {
      content: funcs.loremIpsum({
        // `sentencesCount` - number of sentences you want to generate as one generated value(string).
        sentencesCount: 2,

        // number of elements in each one-dimensional array. 
        // (If specified, arrays will be generated.)
        arraySize: 3
      }),
    },
  },
}));

```

### `point`

<rem025 />
Generates 2D points within specified ranges for x and y coordinates.

|  | param       | default                                                                                 | type
|:-| :--------   | :--------                                                                               | :--------
|  |`isUnique`   |`database column uniqueness`                                                             |`boolean`
|  |`maxXValue`  |``` `10 * 1000` if isUnique equals false``` ``` `10 * count` if isUnique equals true```  |`number`
|  |`minXValue`  |`-maxXValue`                                                                             |`number`
|  |`maxYValue`  |``` `10 * 1000` if isUnique equals false``` ``` `10 * count` if isUnique equals true```  |`number`
|  |`minYValue`  |`-maxYValue`                                                                             |`number`
|  |`arraySize`  |--                                                                                       |`number`


<rem025 />

```ts 
import { seed } from "drizzle-seed";

await seed(db, schema, { count: 1000 }).refine((funcs) => ({
  triangles: {
    columns: {
      pointCoords: funcs.point({
        // `isUnique` - property that controls if generated values gonna be unique or not.
        isUnique: true,

        // `minXValue` - lower bound of range for x coordinate.
        minXValue: -5,

        // `maxXValue` - upper bound of range for x coordinate.
        maxXValue: 20,

        // `minYValue` - lower bound of range for y coordinate.
        minYValue: 0,

        // `maxYValue` - upper bound of range for y coordinate.
        maxYValue: 30,

        // number of elements in each one-dimensional array. 
        // (If specified, arrays will be generated.)
        arraySize: 3
      }),
    },
  },
}));

```

### `line`

<rem025 />
Generates 2D lines within specified ranges for a, b and c parameters of line.

```
line equation: a*x + b*y + c = 0
```

|  | param       | default                                                                                 | type
|:-| :--------   | :--------                                                                               | :--------
|  |`isUnique`   |`database column uniqueness`                                                             |`boolean`
|  |`maxAValue`  |``` `10 * 1000` if isUnique equals false``` ``` `10 * count` if isUnique equals true```  |`number`
|  |`minAValue`  |`-maxAValue`                                                                             |`number`
|  |`maxBValue`  |``` `10 * 1000` if isUnique equals false``` ``` `10 * count` if isUnique equals true```  |`number`
|  |`minBValue`  |`-maxBValue`                                                                             |`number`
|  |`maxCValue`  |``` `10 * 1000` if isUnique equals false``` ``` `10 * count` if isUnique equals true```  |`number`
|  |`minCValue`  |`-maxCValue`                                                                             |`number`
|  |`arraySize`  |--                                                                                       |`number`
<rem025 />

```ts 
import { seed } from "drizzle-seed";

await seed(db, schema, { count: 1000 }).refine((funcs) => ({
  lines: {
    columns: {
      lineParams: funcs.point({
        // `isUnique` - property that controls if generated values gonna be unique or not.
        isUnique: true,

        // `minAValue` - lower bound of range for a parameter.
        minAValue: -5,

        // `maxAValue` - upper bound of range for x parameter.
        maxAValue: 20,

        // `minBValue` - lower bound of range for y parameter.
        minBValue: 0,

        // `maxBValue` - upper bound of range for y parameter.
        maxBValue: 30,

        // `minCValue` - lower bound of range for y parameter.
        minCValue: 0,

        // `maxCValue` - upper bound of range for y parameter.
        maxCValue: 10,

        // number of elements in each one-dimensional array. 
        // (If specified, arrays will be generated.)
        arraySize: 3
      }),
    },
  },
}));

```

### `bitString`

<rem025 />
Generates bit strings based on specified parameters.

|  | param       | default                                                                                 | type
|:-| :--------   | :--------                                                                               | :--------
|  |`isUnique`   |`database column uniqueness`                                                             |`boolean`
|  |`dimensions` |`database column bit-length`                                                             |`number`
|  |`arraySize`  |--                                                                                       |`number`
<rem025 />

```ts 
import { seed } from "drizzle-seed";

await seed(db, schema, { count: 1000 }).refine((funcs) => ({
  bitStringTable: {
    columns: {
      bit: funcs.bitString({
        // desired length of each bit string (e.g., `dimensions = 3` produces values like `'010'`).
        dimensions: 12,

        // property that controls if generated values gonna be unique or not;
        isUnique: true,

        // number of elements in each one-dimensional array (If specified, arrays will be generated);
        arraySize: 3,
      }),
    },
  },
}));

```

### `inet`

<rem025 />
Generates ip addresses based on specified parameters.

|  | param       | default                                                                                 | type
|:-| :--------   | :--------                                                                               | :--------
|  |`isUnique`   |`database column uniqueness`                                                             |`boolean`
|  |`arraySize`  |--                                                                                       |`number`
|  |`ipAddress`  |`'ipv4'`                                                                                 |`'ipv4' \| 'ipv6'`
|  |`includeCidr`|`true`                                                                                   |`boolean`
<rem025 />

```ts 
import { seed } from "drizzle-seed";

await seed(db, schema, { count: 1000 }).refine((funcs) => ({
  inetTable: {
    columns: {
      inet: funcs.inet({
        // property that controls if generated values gonna be unique or not;
        isUnique: true,

        // number of elements in each one-dimensional array (If specified, arrays will be generated);
        arraySize: 3,

        // type of IP address to generate — either "ipv4" or "ipv6";
        ipAddress: "ipv4",

        // determines whether generated IPs include a CIDR suffix.
        includeCidr: true,
      }),
    },
  },
}));
```

### `geometry`

<rem025 />
Generates geometry objects based on the given parameters.

<Callout title='warnings'>
<Tabs items={['arraySize', 'srid']}>
<Tab>
Currently, if you set arraySize to a value greater than 1 
or try to insert more than one `geometry point` element into a `geometry(point, 0)[]` column in MySQL via drizzle-orm, 
you’ll encounter an error.

This bug is already in the backlog.

<Callout title="❌">
```ts {13}
import { seed } from "drizzle-seed";
import { geometry, mysqlTable } from 'drizzle-orm/mysql-core';

const geometryTable = mysqlTable('geometry_table', {
	geometryArray: geometry('geometry_array', { type: 'point', srid: 0 }).array(3),
});

await seed(db, { geometryTable }, { count: 1000 }).refine((funcs) => ({
  geometryTable: {
    columns: {
      geometryArray: funcs.geometry({
        // currently arraySize with values > 1 are not supported
        arraySize: 3,
      }),
    },
  },
}));
```
</Callout>

<Callout title='✅'>
```ts {13}
import { seed } from "drizzle-seed";
import { geometry, mysqlTable } from 'drizzle-orm/mysql-core';

const geometryTable = mysqlTable('geometry_table', {
	geometryArray: geometry('geometry_array', { type: 'point', srid: 0 }).array(1),
});

await seed(db, { geometryTable }, { count: 1000 }).refine((funcs) => ({
  geometryTable: {
    columns: {
      geometryArray: funcs.geometry({
        // will work as expected
        arraySize: 1,
      }),
    },
  },
}));
```
</Callout>
</Tab>

<Tab>
Currently, if you set the SRID of a `geometry(point)` column to anything other than 0 (for example, 4326) in your drizzle-orm table declaration, 
you’ll encounter an error during the seeding process.

This bug is already in the backlog.

<Callout title="❌">
```ts {5}
import { seed } from "drizzle-seed";
import { geometry, mysqlTable } from 'drizzle-orm/mysql-core';

const geometryTable = mysqlTable('geometry_table', {
	geometryColumn: geometry('geometry_column', { type: 'point', srid: 4326 }),
});

await seed(db, { geometryTable }, { count: 1000 }).refine((funcs) => ({
  geometryTable: {
    columns: {
      geometryColumn: funcs.geometry({
        srid: 4326,
      }),
    },
  },
}));
```
</Callout>

<Callout title='✅'>
```ts {5}
import { seed } from "drizzle-seed";
import { geometry, mysqlTable } from 'drizzle-orm/mysql-core';

const geometryTable = mysqlTable('geometry_table', {
	geometryColumn: geometry('geometry_column', { type: 'point', srid: 0 }),
});

await seed(db, { geometryTable }, { count: 1000 }).refine((funcs) => ({
  geometryTable: {
    columns: {
      geometryColumn: funcs.geometry({
        srid: 4326,
      }),
    },
  },
}));
```
</Callout>
</Tab>
</Tabs>
</Callout>

|  | param          | default                                                                                 | type
|:-| :--------      | :--------                                                                               | :--------
|  |`isUnique`      |`database column uniqueness`                                                             |`boolean`
|  |`arraySize`     |--                                                                                       |`number`
|  |`type`          |`'point'`                                                                                |`'point'`
|  |`srid`          |`4326`                                                                                   |`4326 \| 3857`
|  |`decimalPlaces` |`6`                                                                                      |`1 \| 2 \| 3 \| 4 \| 5 \| 6 \| 7`
<rem025 />

```ts 
import { seed } from "drizzle-seed";

await seed(db, schema, { count: 1000 }).refine((funcs) => ({
  geometryTable: {
    columns: {
      geometryPointTuple: funcs.geometry({
        // property that controls if generated values gonna be unique or not;
        isUnique: true,

        // number of elements in each one-dimensional array (If specified, arrays will be generated);
        arraySize: 1,

        // geometry type to generate; currently only `'point'` is supported;
        type: "point",

        // Spatial Reference System Identifier: determines what type of point will be generated - either `4326` or `3857`;
        srid: 4326,

        // number of decimal places for points when `srid` is `4326` (e.g., `decimalPlaces = 3` produces values like `'point(30.723 46.482)'`).
        decimalPlaces: 5,
      }),
    },
  },
}));

```

### `vector`

<rem025 />
Generates vectors based on the provided parameters.

|  | param          | default                                                      | type
|:-| :--------      | :--------                                                    | :--------
|  |`isUnique`      |`database column uniqueness`                                  |`boolean`
|  |`arraySize`     |--                                                            |`number`
|  |`decimalPlaces` |`2`                                                           |`number`
|  |`dimensions`    |`database column’s dimensions`                                |`number`
|  |`minValue`      |`-1000`                                                       |`number`
|  |`maxValue`      |`1000`                                                        |`number`
<rem025 />

```ts 
import { seed } from "drizzle-seed";

await seed(db, schema, { count: 1000 }).refine((funcs) => ({
  vectorTable: {
    columns: {
      vector: funcs.vector({
        // property that controls if generated values gonna be unique or not;
        isUnique: true,

        // number of elements in each one-dimensional array (If specified, arrays will be generated);
        arraySize: 3,

        // number of decimal places for each vector element (e.g., `decimalPlaces = 3` produces values like `1.123`);
        decimalPlaces: 5,

        // number of elements in each generated vector (e.g., `dimensions = 3` produces values like `[1,2,3]`);
        dimensions: 12,

        // minimum allowed value for each vector element;
        minValue: -100,

        // maximum allowed value for each vector element.
        maxValue: 100,
      }),
    },
  },
}));

```

Source: https://orm.drizzle.team/docs/mysql/seed-overview

import Npm from "@mdx/Npm.astro";
import Tab from "@mdx/Tab.astro";
import Tabs from "@mdx/Tabs.astro";
import Callout from '@mdx/Callout.astro';
import CodeTabs from "@mdx/CodeTabs.astro";
import Section from "@mdx/Section.astro";

# Drizzle Seed

`drizzle-seed` is a TypeScript library that helps you generate deterministic, yet realistic,
fake data to populate your database. By leveraging a seedable pseudorandom number generator (pRNG),
it ensures that the data you generate is consistent and reproducible across different runs.
This is especially useful for testing, development, and debugging purposes.

#### What is Deterministic Data Generation?

Deterministic data generation means that the same input will always produce the same output.
In the context of `drizzle-seed`, when you initialize the library with the same seed number,
it will generate the same sequence of fake data every time. This allows for predictable and repeatable data sets.

#### Pseudorandom Number Generator (pRNG)

A pseudorandom number generator is an algorithm that produces a sequence of numbers
that approximates the properties of random numbers. However, because it's based on an initial value
called a seed, you can control its randomness. By using the same seed, the pRNG will produce the
same sequence of numbers, making your data generation process reproducible.

#### Benefits of Using a pRNG:

- Consistency: Ensures that your tests run on the same data every time.
- Debugging: Makes it easier to reproduce and fix bugs by providing a consistent data set.
- Collaboration: Team members can share seed numbers to work with the same data sets.

With drizzle-seed, you get the best of both worlds: the ability to generate realistic fake data and the control to reproduce it whenever needed.

## Installation

<Npm>drizzle-seed</Npm>

## Basic Usage

In this example we will create 10 users with random names and ids

```ts {12}
import { mysqlTable, int, varchar } from "drizzle-orm/mysql-core";
import { drizzle } from "drizzle-orm/mysql2";
import { seed } from "drizzle-seed";

const users = mysqlTable("users", {
  id: int().primaryKey().autoincrement(),
  name: varchar({ length: 255 }).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

```ts
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

```ts
await seed(db, schema, { seed: 12345 });
```

## Reset database

With `drizzle-seed`, you can easily reset your database and seed it with new values, for example, in your test suites

```ts
// path to a file with schema you want to reset
import * as schema from "./schema.ts";
import { reset } from "drizzle-seed";

async function main() {
  const db = drizzle(process.env.DATABASE_URL!);
  await reset(db, schema);
}

main();
```

Different dialects will have different strategies for database resetting. For MySQL:

For MySQL, the `drizzle-seed` package will first disable `FOREIGN_KEY_CHECKS` to ensure the next step won't fail, and then generate `TRUNCATE` statements to empty the content of all tables

```sql
SET FOREIGN_KEY_CHECKS = 0;
TRUNCATE tableName1;
TRUNCATE tableName2;
...
SET FOREIGN_KEY_CHECKS = 1;
```

## Refinements

In case you need to change the behavior of the seed generator functions that `drizzle-seed` uses by default, you can specify your own implementation and even use your own list of values for the seeding process

`.refine` is a callback that receives a list of all available generator functions from `drizzle-seed`. It should return an object with keys representing the tables you want to refine, defining their behavior as needed. 
Each table can specify several properties to simplify seeding your database:

<rem025 />

- `columns`: Refine the default behavior of each column by specifying the required generator function, or exclude the column from seeding by specifying `false`.
- `count`: Specify the number of rows to insert into the database. By default, it's 10. If a global count is defined in the `seed()` options, the count defined here will override it for this specific table.
- `with`: Define how many referenced entities to create for each parent table if you want to generate associated entities.

<Callout title='info'>
You can also specify a weighted random distribution for the number of referenced values you want to create. For details on this API, you can refer to [Weighted Random docs](#weighted-random) docs section
</Callout>

**API**
```ts
await seed(db, schema).refine((f) => ({
  users: {
    columns: {},
    count: 10,
    with: {
        posts: 10
    }
  },
}));
```

Let's check a few examples with an explanation of what will happen:

```ts filename='schema.ts'
import { mysqlTable, int, varchar } from "drizzle-orm/mysql-core";

export const users = mysqlTable("users", {
  id: int().primaryKey().autoincrement(),
  name: varchar({ length: 255 }).notNull(),
});

export const posts = mysqlTable("posts", {
  id: int().primaryKey().autoincrement(),
  description: varchar({ length: 255 }),
  userId: int().references(() => users.id),
});
```

**Example 1**: Seed only the `users` table with 20 entities and with refined seed logic for the `name` column
```ts filename='index.ts'
import { drizzle } from "drizzle-orm/mysql2";
import { seed } from "drizzle-seed";
import * as schema from './schema.ts'

async function main() {
  const db = drizzle(process.env.DATABASE_URL!);

  await seed(db, { users: schema.users }).refine((f) => ({
    users: {
        columns: {
            name: f.fullName(),
        },
        count: 20
    }
  }));
}

main();
```

**Example 2**: Seed only the `users` table, excluding the `name` column from seeding
```ts filename='index.ts'
import { drizzle } from "drizzle-orm/mysql2";
import { seed } from "drizzle-seed";
import * as schema from './schema.ts'

async function main() {
  const db = drizzle(process.env.DATABASE_URL!);

  await seed(db, { users: schema.users }).refine((f) => ({
    users: {
        columns: {
            name: false, // the name column will not be seeded, allowing the database to use its default value.
        }
    }
  }));
}

main();
```

**Example 3**: Seed the `users` table with 20 entities and add 10 `posts` for each `user` by seeding the `posts` table and creating a reference from `posts` to `users`
```ts filename='index.ts'
import { drizzle } from "drizzle-orm/mysql2";
import { seed } from "drizzle-seed";
import * as schema from './schema.ts'

async function main() {
  const db = drizzle(process.env.DATABASE_URL!);

  await seed(db, schema).refine((f) => ({
    users: {
        count: 20,
        with: {
            posts: 10
        }
    }
  }));
}

main();
```

**Example 4**: Seed the `users` table with 5 entities and populate the database with 100 `posts` without connecting them to the `users` entities. Refine `id` generation for `users` so 
that it will give any int from `10000` to `20000` and remains unique, and refine `posts` to retrieve values from a self-defined array
```ts filename='index.ts'
import { drizzle } from "drizzle-orm/mysql2";
import { seed } from "drizzle-seed";
import * as schema from './schema.ts'

async function main() {
  const db = drizzle(process.env.DATABASE_URL!);

  await seed(db, schema).refine((f) => ({
    users: {
        count: 5,
        columns: {
            id: f.int({
              minValue: 10000,
              maxValue: 20000,
              isUnique: true,
            }),
        }
    },
    posts: {
        count: 100,
        columns: {
            description: f.valuesFromArray({
            values: [
                "The sun set behind the mountains, painting the sky in hues of orange and purple", 
                "I can't believe how good this homemade pizza turned out!", 
                "Sometimes, all you need is a good book and a quiet corner.", 
                "Who else thinks rainy days are perfect for binge-watching old movies?", 
                "Tried a new hiking trail today and found the most amazing waterfall!",
                // ...
            ],
          })
        }
    }
  }));
}

main();
```

<Callout type='warning'>
There are many more possibilities that we will define in these docs, but for now, you can explore a few sections in this documentation. Check the [Generators](/docs/mysql/seed-functions) section to get familiar with all the available generator functions you can use.

A particularly great feature is the ability to use weighted randomization, both for generator values created for a column and for determining the number of related entities that can be generated by `drizzle-seed`.

Please check [Weighted Random docs](#weighted-random) for more info.
</Callout>


## Weighted Random

There may be cases where you need to use multiple datasets with a different priority that should be inserted into your database during the seed stage. For such cases, drizzle-seed provides an API called weighted random

The Drizzle Seed package has a few places where weighted random can be used:

- Columns inside each table refinements
- The `with` property, determining the amount of related entities to be created

Let's check an example for both:

```ts filename="schema.ts"
import { mysqlTable, int, varchar, double } from "drizzle-orm/mysql-core";

export const orders = mysqlTable(
  "orders",
  {
    id: int().primaryKey().autoincrement(),
    name: varchar({ length: 255 }).notNull(),
    quantityPerUnit: varchar().notNull(),
    unitPrice: double().notNull(),
    unitsInStock: int().notNull(),
    unitsOnOrder: int().notNull(),
    reorderLevel: int().notNull(),
    discontinued: int().notNull(),
  }
);

export const details = mysqlTable(
  "details",
  {
    unitPrice: double().notNull(),
    quantity: int().notNull(),
    discount: double().notNull(),

    orderId: int()
      .notNull()
      .references(() => orders.id, { onDelete: "cascade" }),
  }
);
```

**Example 1**: Refine the `unitPrice` generation logic to generate `5000` random prices, with a 30% chance of prices between 10-100 and a 70% chance of prices between 100-300

```ts filename="index.ts"
import { drizzle } from "drizzle-orm/mysql2";
import { seed } from "drizzle-seed";
import * as schema from './schema.ts'

async function main() {
  const db = drizzle(process.env.DATABASE_URL!);

  await seed(db, schema).refine((f) => ({
    orders: {
       count: 5000,
       columns: {
           unitPrice: f.weightedRandom(
               [
                   {
                       weight: 0.3,
                       value: funcs.int({ minValue: 10, maxValue: 100 })
                   },
                   {
                       weight: 0.7,
                       value: funcs.number({ minValue: 100, maxValue: 300, precision: 100 })
                   }
               ]
           ),
       }
    }
  }));
}

main();
```

**Example 2**: For each order, generate 1 to 3 details with a 60% chance, 5 to 7 details with a 30% chance, and 8 to 10 details with a 10% chance

```ts filename="index.ts"
import { drizzle } from "drizzle-orm/mysql2";
import { seed } from "drizzle-seed";
import * as schema from './schema.ts'

async function main() {
  const db = drizzle(process.env.DATABASE_URL!);

  await seed(db, schema).refine((f) => ({
    orders: {
       with: {
           details:
               [
                   { weight: 0.6, count: [1, 2, 3] },
                   { weight: 0.3, count: [5, 6, 7] },
                   { weight: 0.1, count: [8, 9, 10] },
               ]
       }
    }
  }));
}

main();
```

## Complex example

<CodeTabs items={["main.ts", "schema.ts"]}>
<Section>
```ts
import { seed } from "drizzle-seed";
import * as schema from "./schema.ts";

const main = async () => {
    const titlesOfCourtesy = ["Ms.", "Mrs.", "Dr."];
    const unitsOnOrders = [0, 10, 20, 30, 50, 60, 70, 80, 100];
    const reorderLevels = [0, 5, 10, 15, 20, 25, 30];
    const quantityPerUnit = [
        "100 - 100 g pieces",
        "100 - 250 g bags",
        "10 - 200 g glasses",
        "10 - 4 oz boxes",
        "10 - 500 g pkgs.",
        "10 - 500 g pkgs."
    ];
    const discounts = [0.05, 0.15, 0.2, 0.25];

    await seed(db, schema).refine((funcs) => ({
        customers: {
            count: 10000,
            columns: {
                companyName: funcs.companyName(),
                contactName: funcs.fullName(),
                contactTitle: funcs.jobTitle(),
                address: funcs.streetAddress(),
                city: funcs.city(),
                postalCode: funcs.postcode(),
                region: funcs.state(),
                country: funcs.country(),
                phone: funcs.phoneNumber({ template: "(###) ###-####" }),
                fax: funcs.phoneNumber({ template: "(###) ###-####" })
            }
        },
        employees: {
            count: 200,
            columns: {
                firstName: funcs.firstName(),
                lastName: funcs.lastName(),
                title: funcs.jobTitle(),
                titleOfCourtesy: funcs.valuesFromArray({ values: titlesOfCourtesy }),
                birthDate: funcs.date({ minDate: "2010-12-31", maxDate: "2010-12-31" }),
                hireDate: funcs.date({ minDate: "2010-12-31", maxDate: "2024-08-26" }),
                address: funcs.streetAddress(),
                city: funcs.city(),
                postalCode: funcs.postcode(),
                country: funcs.country(),
                homePhone: funcs.phoneNumber({ template: "(###) ###-####" }),
                extension: funcs.int({ minValue: 428, maxValue: 5467 }),
                notes: funcs.loremIpsum()
            }
        },
        orders: {
            count: 50000,
            columns: {
                shipVia: funcs.int({ minValue: 1, maxValue: 3 }),
                freight: funcs.number({ minValue: 0, maxValue: 1000, precision: 100 }),
                shipName: funcs.streetAddress(),
                shipCity: funcs.city(),
                shipRegion: funcs.state(),
                shipPostalCode: funcs.postcode(),
                shipCountry: funcs.country()
            },
            with: {
                details:
                    [
                        { weight: 0.6, count: [1, 2, 3, 4] },
                        { weight: 0.2, count: [5, 6, 7, 8, 9, 10] },
                        { weight: 0.15, count: [11, 12, 13, 14, 15, 16, 17] },
                        { weight: 0.05, count: [18, 19, 20, 21, 22, 23, 24, 25] },
                    ]
            }
        },
        suppliers: {
            count: 1000,
            columns: {
                companyName: funcs.companyName(),
                contactName: funcs.fullName(),
                contactTitle: funcs.jobTitle(),
                address: funcs.streetAddress(),
                city: funcs.city(),
                postalCode: funcs.postcode(),
                region: funcs.state(),
                country: funcs.country(),
                phone: funcs.phoneNumber({ template: "(###) ###-####" })
            }
        },
        products: {
            count: 5000,
            columns: {
                name: funcs.companyName(),
                quantityPerUnit: funcs.valuesFromArray({ values: quantityPerUnit }),
                unitPrice: funcs.weightedRandom(
                    [
                        {
                            weight: 0.5,
                            value: funcs.int({ minValue: 3, maxValue: 300 })
                        },
                        {
                            weight: 0.5,
                            value: funcs.number({ minValue: 3, maxValue: 300, precision: 100 })
                        }
                    ]
                ),
                unitsInStock: funcs.int({ minValue: 0, maxValue: 125 }),
                unitsOnOrder: funcs.valuesFromArray({ values: unitsOnOrders }),
                reorderLevel: funcs.valuesFromArray({ values: reorderLevels }),
                discontinued: funcs.int({ minValue: 0, maxValue: 1 })
            }
        },
        details: {
            columns: {
                unitPrice: funcs.number({ minValue: 10, maxValue: 130 }),
                quantity: funcs.int({ minValue: 1, maxValue: 130 }),
                discount: funcs.weightedRandom(
                    [
                        { weight: 0.5, value: funcs.valuesFromArray({ values: discounts }) },
                        { weight: 0.5, value: funcs.default({ defaultValue: 0 }) }
                    ]
                )
            }
        }
    }));
}

main();

```
</Section>
<Section>
```ts
import type { AnyColumn } from "drizzle-orm";
import { int, numeric, mysqlTable, text, timestamp, varchar } from "drizzle-orm/mysql-core";

export const customers = mysqlTable('customer', {
	id: varchar({ length: 256 }).primaryKey(),
	companyName: text().notNull(),
	contactName: text().notNull(),
	contactTitle: text().notNull(),
	address: text().notNull(),
	city: text().notNull(),
	postalCode: text(),
	region: text(),
	country: text().notNull(),
	phone: text().notNull(),
	fax: text(),
});

export const employees = mysqlTable(
	'employee',
	{
		id: int().primaryKey().autoincrement(),
		lastName: text().notNull(),
		firstName: text(),
		title: text().notNull(),
		titleOfCourtesy: text().notNull(),
		birthDate: timestamp().notNull(),
		hireDate: timestamp().notNull(),
		address: text().notNull(),
		city: text().notNull(),
		postalCode: text().notNull(),
		country: text().notNull(),
		homePhone: text().notNull(),
		extension: int().notNull(),
		notes: text().notNull(),
		reportsTo: int().references((): AnyColumn => employees.id),
		photoPath: text(),
	},
);

export const orders = mysqlTable('order', {
	id: int().primaryKey().autoincrement(),
	orderDate: timestamp().notNull(),
	requiredDate: timestamp().notNull(),
	shippedDate: timestamp(),
	shipVia: int().notNull(),
	freight: numeric().notNull(),
	shipName: text().notNull(),
	shipCity: text().notNull(),
	shipRegion: text(),
	shipPostalCode: text(),
	shipCountry: text().notNull(),

	customerId: text().notNull().references(() => customers.id, { onDelete: 'cascade' }),

	employeeId: int().notNull().references(() => employees.id, { onDelete: 'cascade' }),
});

export const suppliers = mysqlTable('supplier', {
	id: int().primaryKey().autoincrement(),
	companyName: text().notNull(),
	contactName: text().notNull(),
	contactTitle: text().notNull(),
	address: text().notNull(),
	city: text().notNull(),
	region: text(),
	postalCode: text().notNull(),
	country: text().notNull(),
	phone: text().notNull(),
});

export const products = mysqlTable('product', {
	id: int().primaryKey().autoincrement(),
	name: varchar({ length: 255 }).notNull(),
	quantityPerUnit: text().notNull(),
	unitPrice: numeric().notNull(),
	unitsInStock: int().notNull(),
	unitsOnOrder: int().notNull(),
	reorderLevel: int().notNull(),
	discontinued: int().notNull(),

	supplierId: int().notNull().references(() => suppliers.id, { onDelete: 'cascade' }),
});

export const details = mysqlTable('order_detail', {
	unitPrice: numeric().notNull(),
	quantity: int().notNull(),
	discount: numeric().notNull(),

	orderId: int().notNull().references(() => orders.id, { onDelete: 'cascade' }),

	productId: int().notNull().references(() => products.id, { onDelete: 'cascade' }),
});

```
</Section>
</CodeTabs>

## Limitations

#### Types limitations for `with`

Due to certain TypeScript limitations and the current API in Drizzle, it is not possible to properly infer references between tables, especially when circular dependencies between tables exist.

This means the `with` option will display all tables in the schema, and you will need to manually select the one that has a one-to-many relationship

<Callout title='warning'>
The `with` option works for one-to-many relationships. For example, if you have one `user` and many `posts`, you can use users `with` posts, but you cannot use posts `with` users
</Callout>

#### Type limitations for the third parameter in Drizzle tables:

Currently, we do not have type support for the third parameter in Drizzle tables. While it will work at runtime, it will not function correctly at the type level


Source: https://orm.drizzle.team/docs/mysql/seed-versioning

import Tab from "@mdx/Tab.astro";
import Tabs from "@mdx/Tabs.astro";
import Callout from "@mdx/Callout.astro";
import TableWrapper from "@mdx/TableWrapper.astro";

# Versioning

`drizzle-seed` uses versioning to manage outputs for static and dynamic data. To ensure true 
determinism, ensure that values remain unchanged when using the same `seed` number. If changes are made to 
static data sources or dynamic data generation logic, the version will be updated, allowing
you to choose between sticking with the previous version or using the latest.

You can upgrade to the latest `drizzle-seed` version for new features, such as additional
generators, while maintaining deterministic outputs with a previous version if needed. This
is particularly useful when you need to rely on existing deterministic data while accessing new functionality.

```ts
await seed(db, schema, { version: '2' });
```

## History
<TableWrapper>
|          api version  |   npm version    |     Changed generators                    |
|  :--------------      | :--------------  | :-------------                            |
|       `v1`            | `0.1.1`          |                                           |
|       `v2`	        | `0.2.1`          |`string()`, `interval({ isUnique: true })` |
|       `v3`            | `0.4.0`          |`hash generating function`    			   |
|       `v4 (LTS) `     | `1.0.0-beta.8`   |`uuid` 								       |
</TableWrapper>

<Callout collapsed="How it works under the hood?">
> This is not an actual API change; it is just an example of how we will proceed with `drizzle-seed` versioning.

For example, `lastName` generator was changed, and new version, `V2`, of this generator became available.

Later, `firstName` generator was changed, making `V3` version of this generator available.

|                  |       `V1`       |      `V2`       |   `V3(latest)`   |
| :--------------: | :--------------: | :-------------: | :--------------: |
| **LastNameGen**  | `LastNameGenV1`  | `LastNameGenV2` |                  |
| **FirstNameGen** | `FirstNameGenV1` |                 | `FirstNameGenV3` |


##### Use the `firstName` generator of version 3 and the `lastName` generator of version 2
```ts
await seed(db, schema);
```

If you are not ready to use latest generator version right away, you can specify max version to use

##### Use the `firstName` generator of version 1 and the `lastName` generator of version 2
```ts
await seed(db, schema, { version: '2' });
```

##### Use the `firstName` generator of version 1 and the `lastName` generator of version 1.
```ts
await seed(db, schema, { version: '1' });
```

</Callout>

## Version 2
#### Unique `interval` generator was changed

<Callout title='Reason for upgrade'>
An older version of the generator could produce intervals like `1 minute 60 seconds` and `2 minutes 0 seconds`, treating them as distinct intervals.
However, when the `1 minute 60 seconds` interval is inserted into a MySQL database, it is automatically converted to `2 minutes 0 seconds`. As a result, attempting to insert the `2 minutes 0 seconds` interval into a unique column afterwards will cause an error
</Callout>


You will be affected, if you use the unique `interval` generator in your seeding script, as shown in the script below:
```ts
import { binary, char, mysqlTable, text, varbinary, varchar } from 'drizzle-orm/mysql-core';
import { drizzle } from 'drizzle-orm/mysql2';
import { seed } from "drizzle-seed";

const intervals = mysqlTable('intervals', {
	interval1: char({ length: 255 }).unique(),
	interval2: char({ length: 255 }),
	interval3: varchar({ length: 255 }).unique(),
	interval4: varchar({ length: 255 }),
	interval5: binary({ length: 255 }).unique(),
	interval6: binary({ length: 255 }),
	interval7: varbinary({ length: 255 }).unique(),
	interval8: varbinary({ length: 255 }),
	interval9: text(),
});

async function main() {
	const db = drizzle(process.env.DATABASE_URL!);

	await seed(db, { intervals }, { version: '2' }).refine((f) => ({
		intervals: {
			columns: {
				interval: f.interval({ isUnique: true }),
				interval1: f.interval({ isUnique: true }),
				interval2: f.interval({ isUnique: true }),
				interval3: f.interval({ isUnique: true }),
				interval4: f.interval({ isUnique: true }),
				interval5: f.interval({ isUnique: true }),
				interval6: f.interval({ isUnique: true }),
				interval7: f.interval({ isUnique: true }),
				interval8: f.interval({ isUnique: true }),
				interval9: f.interval({ isUnique: true }),
			},
		},
	}));
}

main();

```

#### `string` generators were changed: both non-unique and unique

<Callout title='Reason to upgrade'>
Ability to generate a unique string based on the length of the text column (e.g., `varchar(20)`)
</Callout>

You will be affected, if your table includes a column of a text-like type with a maximum length parameter or a unique column of a text-like type:
```ts
import { binary, char, mysqlTable, varbinary, varchar } from 'drizzle-orm/mysql-core';
import { drizzle } from 'drizzle-orm/mysql2';
import { seed } from "drizzle-seed";

const strings = mysqlTable('strings', {
	string1: char({ length: 255 }).unique(),
	string2: char({ length: 255 }),
	string3: varchar({ length: 255 }).unique(),
	string4: varchar({ length: 255 }),
	string5: binary({ length: 255 }).unique(),
	string6: binary({ length: 255 }),
	string7: varbinary({ length: 255 }).unique(),
	string8: varbinary({ length: 255 }),
});

async function main() {
	const db = drizzle(process.env.DATABASE_URL!);

	await seed(db, { strings });
}

main();

```

You will be affected, if you use the `string` generator in your seeding script, as shown in the script below:
```ts
import { binary, char, mysqlTable, text, varbinary, varchar } from 'drizzle-orm/mysql-core';
import { drizzle } from 'drizzle-orm/mysql2';
import { seed } from "drizzle-seed";

const strings = mysqlTable('strings', {
	string1: char({ length: 255 }).unique(),
	string2: char({ length: 255 }),
	string3: char({ length: 255 }),
	string4: varchar({ length: 255 }).unique(),
	string5: varchar({ length: 255 }),
	string6: varchar({ length: 255 }),
	string7: binary({ length: 255 }).unique(),
	string8: binary({ length: 255 }),
	string9: binary({ length: 255 }),
	string10: varbinary({ length: 255 }).unique(),
	string11: varbinary({ length: 255 }),
	string12: varbinary({ length: 255 }),
	string13: text(),
});

async function main() {
	const db = drizzle(process.env.DATABASE_URL!);

	await seed(db, { strings }).refine((f) => ({
		strings: {
			columns: {
				string1: f.string({ isUnique: true }),
				string2: f.string({ isUnique: true }),
				string3: f.string(),
				string4: f.string({ isUnique: true }),
				string5: f.string({ isUnique: true }),
				string6: f.string(),
				string7: f.string({ isUnique: true }),
				string8: f.string({ isUnique: true }),
				string9: f.string(),
				string10: f.string({ isUnique: true }),
				string11: f.string({ isUnique: true }),
				string12: f.string(),
				string13: f.string({ isUnique: true }),
			},
		},
	}));
}

main();
```

## Version 3
#### `hash generating function was changed`

<Callout title='Reason to upgrade'>
The previous version of the hash generating function generated different hashes depending on whether Bun or Node.js was used, and hashes also varied across versions of Node.js.

The new hash generating function will generate the same hash regardless of the version of Node.js or Bun, resulting in deterministic data generation across all versions.
</Callout>

All generators will output different values compared to the previous version, even with the same seed number.

**Usage**
```ts
await seed(db, schema);
// or explicit
await seed(db, schema, { version: '3' });
```

**Switch to the old version**

The previous version of hash generating function is v1.
```ts
await seed(db, schema, { version: '1' });
```
To use the v2 generators while maintaining the v1 hash generating function:
```ts
await seed(db, schema, { version: '2' });
```

## Version 4
#### `uuid` generator was changed

<Callout title='Reason to upgrade'>
UUID values generated by the old version of the `uuid` generator fail Zod’s v4 UUID validation.

example
```ts
import { createSelectSchema } from 'drizzle-zod';
import { seed } from 'drizzle-seed';

await seed(db, { uuidTest: schema.uuidTest }, { count: 1 }).refine((funcs) => ({
		uuidTest: {
			columns: {
				col1: funcs.uuid()
			}
		}
	})
);

const uuidSelectSchema = createSelectSchema(schema.uuidTest);
const res = await db.select().from(schema.uuidTest);
// the line below will throw an error when using old version of uuid generator
uuidSelectSchema.parse(res[0]);
```
</Callout>

**Usage**
```ts
await seed(db, schema);
// or explicit
await seed(db, schema, { version: '4' });
```

**Switch to the old version**

The previous version of `uuid` generator is v1.
```ts
await seed(db, schema, { version: '1' });
```
To use the v2 generators while maintaining the v1 `uuid` generator:
```ts
await seed(db, schema, { version: '2' });
```
To use the v3 generators while maintaining the v1 `uuid` generator:
```ts
await seed(db, schema, { version: '3' });
```


Source: https://orm.drizzle.team/docs/mysql/select

import CodeTabs from '@mdx/CodeTabs.astro';
import Callout from '@mdx/Callout.astro';
import Section from '@mdx/Section.astro';
import $count from '@mdx/$count-mysql.mdx';

# SQL Select
Drizzle provides you the most SQL-like way to fetch data from your database, while remaining type-safe and composable.
It natively supports mostly every query feature and capability of every dialect,
and whatever it doesn't support yet, can be added by the user with the powerful [`sql`](/docs/mysql/sql) operator.

For the following examples, let's assume you have a `users` table defined like this:

```typescript
import { mysqlTable, text, int } from 'drizzle-orm/mysql-core';

export const users = mysqlTable('users', {
  id: int().primaryKey().autoincrement(),
  name: text().notNull(),
  age: int(),
});
```

### Basic select
Select all rows from a table including all columns:

<Section>
```typescript
const result = await db.select().from(users);
/*
  {
    id: number;
    name: string;
    age: number | null;
  }[]
*/
```
```sql
select `id`, `name`, `age` from `users`;
```
</Section>

Notice that the result type is inferred automatically based on the table definition, including columns nullability.

<Callout type="info">
Drizzle always explicitly lists columns in the `select` clause instead of using `select *`.<br />
This is required internally to guarantee the fields order in the query result, and is also generally considered a good practice.
</Callout>

### Partial select
In some cases, you might want to select only a subset of columns from a table.
You can do that by providing a selection object to the `.select()` method:
<Section>
```typescript copy
const result = await db.select({
  field1: users.id,
  field2: users.name,
}).from(users);

const { field1, field2 } = result[0];
```
```sql
select `id`, `name` from `users`;
```
</Section>

Like in SQL, you can use arbitrary expressions as selection fields, not just table columns:

<Section>
```typescript
const result = await db.select({
  id: users.id,
  lowerName: sql<string>`lower(${users.name})`,
}).from(users);
```
```sql
select `id`, lower(`name`) from `users`;
```
</Section>

<Callout type="warning">
By specifying `sql<string>`, you are telling Drizzle that the **expected** type of the field is `string`.<br />
If you specify it incorrectly (e.g. use `sql<number>` for a field that will be returned as a string), the runtime value won't match the expected type.
Drizzle cannot perform any type casts based on the provided type generic, because that information is not available at runtime.

If you need to apply runtime transformations to the returned value, you can use the [`.mapWith()`](/docs/mysql/sql#sqlmapwith) method.
</Callout>

You can also specify column alias
```ts
const result = await db.select({
  id: users.id,
  lowerName: users.name.as("lower"),
}).from(users);
```
```sql
select `id`, `name` as `lower` from `users`
```

### Conditional select

You can have a dynamic selection object based on some condition:

```typescript
async function selectUsers(withName: boolean) {
  return db
    .select({
      id: users.id,
      ...(withName ? { name: users.name } : {}),
    })
    .from(users);
}

const result = await selectUsers(true);
```

### Distinct select

You can use `.selectDistinct()` instead of `.select()` to retrieve only unique rows from a dataset:
<Section>
```ts
await db.selectDistinct().from(users).orderBy(users.id, users.name);

await db.selectDistinct({ id: users.id }).from(users).orderBy(users.id);
```
```sql
select distinct `id`, `name` from `users` order by `users`.`id`, `users`.`name`;

select distinct `id` from `users` order by `users`.`id`;
```
</Section>

### Advanced select
Powered by TypeScript, Drizzle APIs let you build your select queries in a variety of flexible ways.

Sneak peek of advanced partial select, for more detailed advanced usage examples - see our [dedicated guide](/docs/mysql/guides/include-or-exclude-columns).

<br/>

<CodeTabs items={["example 1", "example 2", "example 3", "example 4"]}>
```ts
import { getColumns, sql } from 'drizzle-orm';

await db.select({
    ...getColumns(posts),
    titleLength: sql<number>`length(${posts.title})`,
  }).from(posts);
```
```ts
import { getColumns } from 'drizzle-orm';

const { content, ...rest } = getColumns(posts); // exclude "content" column
await db.select({ ...rest }).from(posts); // select all other columns
```
```ts
await db.query.posts.findMany({
  columns: {
    title: true,
  },
});
```
```ts
await db.query.posts.findMany({
  columns: {
    content: false,
  },
});
```
</CodeTabs>

## ---

### Filters

You can filter the query results using the [filter operators](/docs/mysql/operators) in the `.where()` method:

<Section>
```typescript copy
import { eq, lt, gte, ne } from 'drizzle-orm';

await db.select().from(users).where(eq(users.id, 42));
await db.select().from(users).where(lt(users.id, 42));
await db.select().from(users).where(gte(users.id, 42));
await db.select().from(users).where(ne(users.id, 42));
...
```
```sql
select `id`, `name`, `age` from `users` where `users`.`id` = 42;
select `id`, `name`, `age` from `users` where `users`.`id` < 42;
select `id`, `name`, `age` from `users` where `users`.`id` >= 42;
select `id`, `name`, `age` from `users` where `users`.`id` <> 42;
```
</Section>

All filter operators are implemented using the [`sql`](/docs/mysql/sql) function.
You can use it yourself to write arbitrary SQL filters, or build your own operators.
For inspiration, you can check how the operators provided by Drizzle are [implemented](https://github.com/drizzle-team/drizzle-orm/blob/main/drizzle-orm/src/sql/expressions/conditions.ts).
<Section>
```typescript copy
import { sql } from 'drizzle-orm';

function equals42(col: Column) {
  return sql`${col} = 42`;
}

await db.select().from(users).where(sql`${users.id} < 42`);
await db.select().from(users).where(sql`${users.id} = 42`);
await db.select().from(users).where(equals42(users.id));
await db.select().from(users).where(sql`${users.id} >= 42`);
await db.select().from(users).where(sql`${users.id} <> 42`);
await db.select().from(users).where(sql`lower(${users.name}) = 'aaron'`);
```
```sql
select `id`, `name`, `age` from `users` where `users`.`id` < 42;
select `id`, `name`, `age` from `users` where `users`.`id` = 42;
select `id`, `name`, `age` from `users` where `users`.`id` = 42;
select `id`, `name`, `age` from `users` where `users`.`id` >= 42;
select `id`, `name`, `age` from `users` where `users`.`id` <> 42;
select `id`, `name`, `age` from `users` where lower(`users`.`name`) = 'aaron';
```
</Section>

<Callout type='info'>
All the values provided to filter operators and to the `sql` function are parameterized automatically.
For example, this query:
```ts
await db.select().from(users).where(eq(users.id, 42));
```
will be translated to:
```sql
select `id`, `name`, `age` from `users` where `id` = ?; -- params: [42]
```
</Callout>

Inverting condition with a `not` operator:
<Section>
```typescript copy
import { eq, not, sql } from 'drizzle-orm';

await db.select().from(users).where(not(eq(users.id, 42)));
await db.select().from(users).where(sql`not ${users.id} = 42`);
```
```sql
select `id`, `name`, `age` from `users` where not (`users`.`id` = 42);
select `id`, `name`, `age` from `users` where not `users`.`id` = 42;
```
</Section>

<Callout type="info">
You can safely alter schema, rename tables and columns
and it will be automatically reflected in your queries because of template interpolation,
as opposed to hardcoding column or table names when writing raw SQL.
</Callout>

### Combining filters
You can logically combine filter operators with `and()` and `or()` operators:
<Section>
```typescript copy
import { eq, and, sql } from 'drizzle-orm';

await db.select().from(users).where(
  and(
    eq(users.id, 42),
    eq(users.name, 'Dan')
  )
);
await db.select().from(users).where(sql`${users.id} = 42 and ${users.name} = 'Dan'`);
```
```sql
select `id`, `name`, `age` from `users` where ((`users`.`id` = 42) and (`users`.`name` = 'Dan'));
select `id`, `name`, `age` from `users` where `users`.`id` = 42 and `users`.`name` = 'Dan';
```
</Section>

<Section>
```typescript copy
import { eq, or, sql } from 'drizzle-orm';

await db.select().from(users).where(
  or(
    eq(users.id, 42), 
    eq(users.name, 'Dan')
  )
);
await db.select().from(users).where(sql`${users.id} = 42 or ${users.name} = 'Dan'`);
```
```sql
select `id`, `name`, `age` from `users` where ((`users`.`id` = 42) or (`users`.`name` = 'Dan'));
select `id`, `name`, `age` from `users` where `users`.`id` = 42 or `users`.`name` = 'Dan';
```
</Section>

### Advanced filters
In combination with TypeScript, Drizzle APIs provide you powerful and flexible ways to combine filters in queries.

Sneak peek of conditional filtering, for more detailed advanced usage examples - see our [dedicated guide](/docs/mysql/guides/conditional-filters-in-query).
<CodeTabs items={["example 1", "example 2"]}>
```ts
const searchPosts = async (term?: string) => {
  await db
    .select()
    .from(posts)
    .where(term ? like(posts.title, term) : undefined);
};
await searchPosts();
await searchPosts('AI');
```
```ts
const searchPosts = async (filters: SQL[]) => {
  await db
    .select()
    .from(posts)
    .where(and(...filters));
};
const filters: SQL[] = [];
filters.push(like(posts.title, 'AI'));
filters.push(inArray(posts.category, ['Tech', 'Art', 'Science']));
filters.push(gt(posts.views, 200));
await searchPosts(filters);
```
</CodeTabs>

## ---

### Limit & offset
Use `.limit()` and `.offset()` to add limit and offset clauses to the query - for example, to implement pagination:

```ts
await db.select().from(users).limit(10);
await db.select().from(users).limit(10).offset(10);
```

```sql
select `id`, `name`, `age` from `users` limit 10;
select `id`, `name`, `age` from `users` limit 10 offset 10;
```

### Order By
Use `.orderBy()` to add `order by` clause to the query, sorting the results by the specified fields:
<Section>
```typescript
import { asc, desc } from 'drizzle-orm';

await db.select().from(users).orderBy(users.name);
await db.select().from(users).orderBy(desc(users.name));

// order by multiple fields
await db.select().from(users).orderBy(users.name, users.name2);
await db.select().from(users).orderBy(asc(users.name), desc(users.name2));
```
```sql
select `id`, `name`, `age`, `name2` from `users` order by `users`.`name`;
select `id`, `name`, `age`, `name2` from `users` order by `users`.`name` desc;

select `id`, `name`, `age`, `name2` from `users` order by `users`.`name`, `users`.`name2`;
select `id`, `name`, `age`, `name2` from `users` order by `users`.`name` asc, `users`.`name2` desc;
```
</Section>

### Advanced pagination
Powered by TypeScript, Drizzle APIs let you implement all possible SQL pagination and sorting approaches.

Sneak peek of advanced pagination, for more detailed advanced
usage examples - see our dedicated [limit offset pagination](/docs/mysql/guides/limit-offset-pagination)
and [cursor pagination](/docs/mysql/guides/cursor-based-pagination) guides.

<CodeTabs items={["example 1", "example 2", "example 3", "example 4"]}>
```ts
await db
  .select()
  .from(users)
  .orderBy(asc(users.id)) // order by is mandatory
  .limit(4) // the number of rows to return
  .offset(4); // the number of rows to skip
```
```ts
const getUsers = async (page = 1, pageSize = 3) => {
  return await db.query.users.findMany({
    orderBy: (users, { asc }) => asc(users.id),
    limit: pageSize,
    offset: (page - 1) * pageSize,
  });
};
await getUsers();
```
```ts
const getUsers = async (page = 1, pageSize = 10) => {
   const sq = db
    .select({ id: users.id })
    .from(users)
    .orderBy(users.id)
    .limit(pageSize)
    .offset((page - 1) * pageSize)
    .as('subquery');
   return await db.select().from(users).innerJoin(sq, eq(users.id, sq.id)).orderBy(users.id);
};
```
```ts
const nextUserPage = async (cursor?: number, pageSize = 3) => {
  return await db
    .select()
    .from(users)
    .where(cursor ? gt(users.id, cursor) : undefined) // if cursor is provided, get rows after it
    .limit(pageSize) // the number of rows to return
    .orderBy(asc(users.id)); // ordering
};
// pass the cursor of the last row of the previous page (id)
await nextUserPage(3);
```
</CodeTabs>

## ---

### WITH clause

Using the `with` clause can help you simplify complex queries by splitting them into smaller subqueries called common table expressions (CTEs):
<Section>
```typescript copy
const sq = db.$with('sq').as(db.select().from(users).where(eq(users.id, 42)));

const result = await db.with(sq).select().from(sq);
```
```sql
with `sq` as (select `id`, `name`, `age` from `users` where `users`.`id` = 42) 
select `id`, `name`, `age` from `sq`
```
</Section>

MySQL doesn't support native `RETURNING`, so `insert`, `update`, and `delete` statements that depend on returning rows are not available inside `with` for this dialect.

To select arbitrary SQL values as fields in a CTE and reference them in other CTEs or in the main query,
you need to add aliases to them:
```typescript copy

const sq = db.$with('sq').as(db.select({ 
  name: sql<string>`upper(${users.name})`.as('name'),
})
.from(users));

const result = await db.with(sq).select({ name: sq.name }).from(sq);
```
If you don't provide an alias, the field type will become `DrizzleTypeError` and you won't be able to reference it in other queries.
If you ignore the type error and still try to use the field,
you will get a runtime error, since there's no way to reference that field without an alias.

### Select from subquery
Just like in SQL, you can embed queries into other queries by using the subquery API:
<Section>
```typescript copy
const sq = db.select().from(users).where(eq(users.id, 42)).as('sq');
const result = await db.select().from(sq);
```
```sql
select `id`, `name`, `age` from (select `id`, `name`, `age` from `users` where `users`.`id` = 42) `sq`;
```
</Section>

Subqueries can be used in any place where a table can be used, for example in joins:
<Section>
```typescript copy
const sq = db.select().from(users).where(eq(users.id, 42)).as('sq');
const result = await db.select().from(users).leftJoin(sq, eq(users.id, sq.id));
```
```sql
select `users`.`id`, `users`.`name`, `users`.`age`, `sq`.`id`, `sq`.`name`, `sq`.`age` from `users` 
  left join (select `id`, `name`, `age` from `users` where `users`.`id` = 42) `sq` 
    on `users`.`id` = `sq`.`id`;
```
</Section>

## ---

### Aggregations
With Drizzle, you can do aggregations using functions like `sum`, `count`, `avg`, etc. by
grouping and filtering with `.groupBy()` and `.having()` respectfully, same as you would do in raw SQL:

<Section>
```typescript
import { gt } from 'drizzle-orm';

await db.select({
  age: users.age,
  count: sql<number>`cast(count(${users.id}) as signed)`,
})
  .from(users)
  .groupBy(users.age);

await db.select({
  age: users.age,
  count: sql<number>`cast(count(${users.id}) as signed)`,
})
  .from(users)
  .groupBy(users.age)
  .having(({ count }) => gt(count, 1));
```
```sql
select `age`, cast(count(`id`) as signed)
  from `users`
  group by `users`.`age`;

select `age`, cast(count(`id`) as signed)
  from `users`
  group by `users`.`age`
  having cast(count(`users`.`id`) as signed) > 1;
```
</Section>

<Callout type="info">
Alternatively, you can use [`.mapWith(Number)`](/docs/mysql/sql#sqlmapwith) to cast the value to a number at runtime.

If you need count aggregation - we recommend using our [`$count`](/docs/mysql/select#count) API
</Callout>

### Aggregations helpers

Drizzle has a set of wrapped `sql` functions, so you don't need to write
`sql` templates for common cases in your app

<Callout type="info">
 Remember, aggregation functions are often used with the GROUP BY clause of the SELECT statement. 
 So if you are selecting using aggregating functions and other columns in one query, 
 be sure to use the `.groupBy` clause
</Callout>

**count**

Returns the number of values in `expression`.
<Section>
```ts
import { count } from 'drizzle-orm'

await db.select({ value: count() }).from(users);
await db.select({ value: count(users.id) }).from(users);
```
```sql
select count(*) from `users`;
select count(`id`) from `users`;
```
```ts
// It's equivalent to writing
await db.select({ 
  value: sql`count(*)`.mapWith(Number) 
}).from(users);

await db.select({ 
  value: sql`count(${users.id})`.mapWith(Number) 
}).from(users);
```
</Section>

**countDistinct**

Returns the number of non-duplicate values in `expression`.
<Section>
```ts
import { countDistinct } from 'drizzle-orm'

await db.select({ value: countDistinct(users.id) }).from(users);
```
```sql
select count(distinct `id`) from `users`;
```
```ts
// It's equivalent to writing
await db.select({ 
  value: sql`count(distinct ${users.id})`.mapWith(Number) 
}).from(users);
```
</Section>

**avg**

Returns the average (arithmetic mean) of all non-null values in `expression`.
<Section>
```ts
import { avg } from 'drizzle-orm'

await db.select({ value: avg(users.id) }).from(users);
```
```sql
select avg(`id`) from `users`;
```
```ts
// It's equivalent to writing
await db.select({ 
  value: sql`avg(${users.id})`.mapWith(String) 
}).from(users);
```
</Section>

**avgDistinct**

Returns the average (arithmetic mean) of all non-null values in `expression`.
<Section>
```ts
import { avgDistinct } from 'drizzle-orm'

await db.select({ value: avgDistinct(users.id) }).from(users);
```
```sql
select avg(distinct `id`) from `users`;
```
```ts
// It's equivalent to writing
await db.select({ 
  value: sql`avg(distinct ${users.id})`.mapWith(String) 
}).from(users);
```
</Section>

**sum**

Returns the sum of all non-null values in `expression`.
<Section>
```ts
import { sum } from 'drizzle-orm'

await db.select({ value: sum(users.id) }).from(users);
```
```sql
select sum(`id`) from `users`;
```
```ts
// It's equivalent to writing
await db.select({ 
  value: sql`sum(${users.id})`.mapWith(String) 
}).from(users);
```
</Section>

**sumDistinct**

Returns the sum of all non-null and non-duplicate values in `expression`.
<Section>
```ts
import { sumDistinct } from 'drizzle-orm'

await db.select({ value: sumDistinct(users.id) }).from(users);
```
```sql
select sum(distinct `id`) from `users`;
```
```ts
// It's equivalent to writing
await db.select({ 
  value: sql`sum(distinct ${users.id})`.mapWith(String) 
}).from(users);
```
</Section>

**max**

Returns the maximum value in `expression`.
<Section>
```ts
import { max } from 'drizzle-orm'

await db.select({ value: max(users.id) }).from(users);
```
```sql
select max(`id`) from `users`;
```
```ts
// It's equivalent to writing
await db.select({ 
  value: sql`max(${expression})`.mapWith(users.id) 
}).from(users);
```
</Section>

**min**

Returns the minimum value in `expression`.
<Section>
```ts
import { min } from 'drizzle-orm'

await db.select({ value: min(users.id) }).from(users);
```
```sql
select min(`id`) from `users`;
```
```ts
// It's equivalent to writing
await db.select({ 
  value: sql`min(${users.id})`.mapWith(users.id) 
}).from(users);
```
</Section>

A more advanced example:

```typescript copy
const orders = mysqlTable("order", {
  id: int().primaryKey(),
  orderDate: int("order_date").notNull(),
  requiredDate: int("required_date").notNull(),
  shippedDate: int("shipped_date"),
  shipVia: int("ship_via").notNull(),
  freight: decimal().notNull(),
  shipName: text("ship_name").notNull(),
  shipCity: text("ship_city").notNull(),
  shipRegion: text("ship_region"),
  shipPostalCode: text("ship_postal_code"),
  shipCountry: text("ship_country").notNull(),
  customerId: text("customer_id").notNull(),
  employeeId: int("employee_id").notNull(),
});

const details = mysqlTable("order_detail", {
  unitPrice: decimal("unit_price").notNull(),
  quantity: int("quantity").notNull(),
  discount: decimal().notNull(),
  orderId: int("order_id").notNull(),
  productId: int("product_id").notNull(),
});

await db.select({
  id: orders.id,
  shippedDate: orders.shippedDate,
  shipName: orders.shipName,
  shipCity: orders.shipCity,
  shipCountry: orders.shipCountry,
  productsCount: sql<number>`cast(count(${details.productId}) as signed)`,
  quantitySum: sql<number>`sum(${details.quantity})`,
  totalPrice: sql<number>`sum(${details.quantity} * ${details.unitPrice})`,
})
  .from(orders)
  .leftJoin(details, eq(orders.id, details.orderId))
  .groupBy(orders.id)
  .orderBy(asc(orders.id));
```

### $count
<$count/>

## ---

### Iterator

If you need to return a very large amount of rows from a query and you don't want to load them all into memory, you can use `.iterator()` to convert the query into an async iterator:

```ts copy
const iterator = db.select().from(users).iterator();

for await (const row of iterator) {
  console.log(row);
}
```

It also works with prepared statements:

```ts copy
const query = db.select().from(users).prepare();
const iterator = query.iterator();

for await (const row of iterator) {
  console.log(row);
}
```

## ---

### Use Index

The `USE INDEX` hint suggests to the optimizer which indexes to consider when processing the query. The optimizer is not forced to use these indexes but will prioritize them if they are suitable.

```ts copy
export const users = mysqlTable('users', {
	id: int().primaryKey(),
	name: varchar({ length: 100 }).notNull(),
}, () => [usersTableNameIndex]);

const usersTableNameIndex = index('users_name_index').on(users.name);

await db.select()
  .from(users, { useIndex: usersTableNameIndex })
  .where(eq(users.name, 'David'));
```

You can also use this option on any join you want

```ts
await db.select()
  .from(users)
  .leftJoin(posts, eq(posts.userId, users.id), { useIndex: usersTableNameIndex })
  .where(eq(users.name, 'David'));
```

### Ignore Index

The `IGNORE INDEX` hint tells the optimizer to avoid using specific indexes for the query. MySQL will consider all other indexes (if any) or perform a full table scan if necessary.

```ts copy
export const users = mysqlTable('users', {
	id: int().primaryKey(),
	name: varchar({ length: 100 }).notNull(),
}, () => [usersTableNameIndex]);

const usersTableNameIndex = index('users_name_index').on(users.name);

await db.select()
  .from(users, { ignoreIndex: usersTableNameIndex })
  .where(eq(users.name, 'David'));
```

You can also use this option on any join you want

```ts
await db.select()
  .from(users)
  .leftJoin(posts, eq(posts.userId, users.id), { ignoreIndex: usersTableNameIndex })
  .where(eq(users.name, 'David'));
```

### Force Index

The `FORCE INDEX` hint forces the optimizer to use the specified index(es) for the query. If the specified index cannot be used, MySQL will not fall back to other indexes; it might resort to a full table scan instead.

```ts copy
export const users = mysqlTable('users', {
	id: int().primaryKey(),
	name: varchar({ length: 100 }).notNull(),
}, () => [usersTableNameIndex]);

const usersTableNameIndex = index('users_name_index').on(users.name);

await db.select()
  .from(users, { forceIndex: usersTableNameIndex })
  .where(eq(users.name, 'David'));
```

You can also use this option on any join you want

```ts
await db.select()
  .from(users)
  .leftJoin(posts, eq(posts.userId, users.id), { forceIndex: usersTableNameIndex })
  .where(eq(users.name, 'David'));
```


Source: https://orm.drizzle.team/docs/mysql/set-operations

import CodeTabs from '@mdx/CodeTabs.astro';
import CodeTab from '@mdx/CodeTab.astro';
import Callout from '@mdx/Callout.astro';

# Set Operations

SQL set operations combine the results of multiple query blocks into a single result. 
The SQL standard defines the following three set operations: `UNION`, `INTERSECT`, `EXCEPT`, `UNION ALL`, `INTERSECT ALL`, `EXCEPT ALL`.

### Union
Combine all results from two query blocks into a single result, omitting any duplicates.

Get all names from customers and users tables without duplicates.

<CodeTabs items={["import-pattern", "builder-pattern", "schema.ts"]}>
	<CodeTab>
	```typescript copy
    import { union } from 'drizzle-orm/mysql-core'
    import { users, customers } from './schema'

    const allNamesForUserQuery = db.select({ name: users.name }).from(users);

    const result = await union(
		allNamesForUserQuery,
		db.select({ name: customers.name }).from(customers)
	).limit(10);
    ```
    ```sql
    (select `name` from `sellers`)
    union
    (select `name` from `customers`)
    limit 10
    ```
	</CodeTab>
    <CodeTab>
    ```ts copy
    import { users, customers } from './schema'

    const result = await db
      .select({ name: users.name })
      .from(users)
      .union(db.select({ name: customers.name }).from(customers))
      .limit(10);
    ```
    ```sql
    (select `name` from `sellers`)
    union
    (select `name` from `customers`)
    limit 10
    ```
    </CodeTab>
    <CodeTab>
	```typescript copy
    import { int, mysqlTable, text, varchar } from "drizzle-orm/mysql-core";

    export const users = mysqlTable('sellers', {
        id: int().primaryKey(),
        name: varchar({ length: 256 }).notNull(),
        address: text(),
    });
    
    export const customers = mysqlTable('customers', {
        id: int().primaryKey(),
        name: varchar(, { length: 256 }).notNull(),
        city: text(),
        email: varchar({ length: 256 }).notNull()
    });
    ```
    </CodeTab>
  </CodeTabs>

### Union All
Combine all results from two query blocks into a single result, with duplicates.

Let's consider a scenario where you have two tables, one representing online sales and the other 
representing in-store sales. In this case, you want to combine the data from both tables into a
single result set. Since there might be duplicate transactions, 
you want to keep all the records and not eliminate duplicates.

<CodeTabs items={["import-pattern", "builder-pattern", "schema.ts"]}>
	<CodeTab>
	```typescript copy
    import { unionAll } from 'drizzle-orm/mysql-core'
    import { onlineSales, inStoreSales } from './schema'

    const onlineTransactions = db.select({ transaction: onlineSales.transactionId }).from(onlineSales);
    const inStoreTransactions = db.select({ transaction: inStoreSales.transactionId }).from(inStoreSales);

    const result = await unionAll(onlineTransactions, inStoreTransactions);
    ```
    ```sql
    (select `transaction_id` from `online_sales`)
    union all
    (select `transaction_id` from `in_store_sales`)
    ```
    </CodeTab>
    <CodeTab>
    ```ts copy
    import { onlineSales, inStoreSales } from './schema'

    const result = await db
      .select({ transaction: onlineSales.transactionId })
      .from(onlineSales)
      .unionAll(
        db.select({ transaction: inStoreSales.transactionId }).from(inStoreSales)
      );
    ```
    ```sql
    (select `transaction_id` from `online_sales`)
    union all
    (select `transaction_id` from `in_store_sales`)
    ```
	</CodeTab>
    <CodeTab>
	```typescript copy
    import { int, mysqlTable, timestamp } from "drizzle-orm/mysql-core";

    export const onlineSales = mysqlTable('online_sales', {
        transactionId: int('transaction_id').primaryKey(),
        productId: int('product_id').unique(),
        quantitySold: int('quantity_sold'),
        saleDate: timestamp('sale_date', { mode: 'date' }),
    });
    
    export const inStoreSales = mysqlTable('in_store_sales', {
        transactionId: int('transaction_id').primaryKey(),
        productId: int('product_id').unique(),
        quantitySold: int('quantity_sold'),
        saleDate: timestamp('sale_date', { mode: 'date' }),
    });
    ```
    </CodeTab>
  </CodeTabs>

### Intersect
Combine only those rows which the results of two query blocks have in common, omitting any duplicates.

Suppose you have two tables that store information about students' course enrollments. 
You want to find the courses that are common between two different departments,
but you want distinct course names, and you're not interested in counting multiple 
enrollments of the same course by the same student.

In this scenario, you want to find courses that are common between the two departments but don't want 
to count the same course multiple times even if multiple students from the same department are enrolled in it.

<CodeTabs items={["import-pattern", "builder-pattern", "schema.ts"]}>
	<CodeTab>
	```typescript copy
    import { intersect } from 'drizzle-orm/mysql-core'
    import { depA, depB } from './schema'

    const departmentACourses = db.select({ courseName: depA.courseName }).from(depA);
    const departmentBCourses = db.select({ courseName: depB.courseName }).from(depB);

    const result = await intersect(departmentACourses, departmentBCourses);
    ```
    ```sql
    (select `course_name` from `department_a_courses`)
    intersect
    (select `course_name` from `department_b_courses`)
    ```
	</CodeTab>
    <CodeTab>
    ```typescript copy
    import { depA, depB } from './schema'

    const result = await db
      .select({ courseName: depA.courseName })
      .from(depA)
      .intersect(db.select({ courseName: depB.courseName }).from(depB));
    ```
    ```sql
    (select `course_name` from `department_a_courses`)
    intersect
    (select `course_name` from `department_b_courses`)
    ```
    </CodeTab>
    <CodeTab>
	```typescript copy
    import { int, mysqlTable, varchar } from "drizzle-orm/mysql-core";

    export const depA = mysqlTable('department_a_courses', {
        studentId: int('student_id'),
        courseName: varchar('course_name', { length: 256 }).notNull(),
    });
    
    export const depB = mysqlTable('department_b_courses', {
        studentId: int('student_id'),
        courseName: varchar('course_name', { length: 256 }).notNull(),
    });
    ```
    </CodeTab>
  </CodeTabs>

### Intersect All
Combine only those rows which the results of two query blocks have in common, with duplicates.

Let's consider a scenario where you have two tables containing data about customer orders, and you want 
to identify products that are ordered by both regular customers and VIP customers. In this case, 
you want to keep track of the quantity of each product, even if it's ordered multiple times by 
different customers.

In this scenario, you want to find products that are ordered by both regular customers and VIP customers, 
but you want to retain the quantity information, even if the same product is ordered multiple 
times by different customers.

<CodeTabs items={["import-pattern", "builder-pattern", "schema.ts"]}>
	<CodeTab>
	```typescript copy
    import { intersectAll } from 'drizzle-orm/mysql-core'
    import { regularCustomerOrders, vipCustomerOrders } from './schema'

    const regularOrders = db.select({ 
        productId: regularCustomerOrders.productId,
        quantityOrdered: regularCustomerOrders.quantityOrdered }
    ).from(regularCustomerOrders);

    const vipOrders = db.select({ 
        productId: vipCustomerOrders.productId,
        quantityOrdered: vipCustomerOrders.quantityOrdered }
    ).from(vipCustomerOrders);

    const result = await intersectAll(regularOrders, vipOrders);
    ```
    ```sql
    (select `product_id`, `quantity_ordered` from `regular_customer_orders`)
    intersect all
    (select `product_id`, `quantity_ordered` from `vip_customer_orders`)
    ```
	</CodeTab>
    <CodeTab>
    ```ts copy
    import { regularCustomerOrders, vipCustomerOrders } from './schema'

    const result = await db
        .select({
          productId: regularCustomerOrders.productId,
          quantityOrdered: regularCustomerOrders.quantityOrdered,
        })
        .from(regularCustomerOrders)
        .intersectAll(
          db
            .select({
              productId: vipCustomerOrders.productId,
              quantityOrdered: vipCustomerOrders.quantityOrdered,
            })
            .from(vipCustomerOrders)
        );
    ```
    ```sql
    (select `product_id`, `quantity_ordered` from `regular_customer_orders`)
    intersect all
    (select `product_id`, `quantity_ordered` from `vip_customer_orders`)
    ```
    </CodeTab>
    <CodeTab>
	```typescript copy
    import { int, mysqlTable } from "drizzle-orm/mysql-core";

    export const regularCustomerOrders = mysqlTable('regular_customer_orders', {
        customerId: int('customer_id').primaryKey(),
        productId: int('product_id').notNull(),
        quantityOrdered: int('quantity_ordered').notNull(),
    });
    
    export const vipCustomerOrders = mysqlTable('vip_customer_orders', {
        customerId: int('customer_id').primaryKey(),
        productId: int('product_id').notNull(),
        quantityOrdered: int('quantity_ordered').notNull(),
    });
    ```
    </CodeTab>
  </CodeTabs>

### Except
For two query blocks A and B, return all results from A which are not also present in B, omitting any duplicates.

Suppose you have two tables that store information about employees' project assignments. 
You want to find the projects that are unique to one department 
and not shared with another department, excluding duplicates.

In this scenario, you want to identify the projects that are exclusive to one department and
not shared with the other department. You don't want to count the same project 
multiple times, even if multiple employees from the same department are assigned to it.

<CodeTabs items={["import-pattern", "builder-pattern", "schema.ts"]}>
	<CodeTab>
	```typescript copy
    import { except } from 'drizzle-orm/mysql-core'
    import { depA, depB } from './schema'

    const departmentACourses = db.select({ courseName: depA.projectsName }).from(depA);
    const departmentBCourses = db.select({ courseName: depB.projectsName }).from(depB);

    const result = await except(departmentACourses, departmentBCourses);
    ```
    ```sql
    (select `projects_name` from `department_a_projects`)
    except
    (select `projects_name` from `department_b_projects`)
    ```
	</CodeTab>
    <CodeTab>
    ```ts copy
    import { depA, depB } from './schema'

    const result = await db
        .select({ courseName: depA.projectsName })
        .from(depA)
        .except(db.select({ courseName: depB.projectsName }).from(depB));
    ```
    ```sql
    (select `projects_name` from `department_a_projects`)
    except
    (select `projects_name` from `department_b_projects`)
    ```
    </CodeTab>
    <CodeTab>
	```typescript 
    import { int, mysqlTable, varchar } from "drizzle-orm/mysql-core";

    export const depA = mysqlTable('department_a_projects', {
        employeeId: int('employee_id'),
        projectsName: varchar('projects_name', { length: 256 }).notNull(),
    });
    
    export const depB = mysqlTable('department_b_projects', {
        employeeId: int('employee_id'),
        projectsName: varchar('projects_name', { length: 256 }).notNull(),
    });
    ```
    </CodeTab>
  </CodeTabs>

### Except All
For two query blocks A and B, return all results from A which are not also present in B, with duplicates.

Let's consider a scenario where you have two tables containing data about customer orders, and you want to 
identify products that are exclusively ordered by regular customers (without VIP customers). 
In this case, you want to keep track of the quantity of each product, even if it's ordered multiple times by different regular customers.

In this scenario, you want to find products that are exclusively ordered by regular customers and not 
ordered by VIP customers. You want to retain the quantity information, even if the same product is ordered multiple times by different regular customers.

<CodeTabs items={["import-pattern", "builder-pattern", "schema.ts"]}>
	<CodeTab>
	```typescript copy
    import { exceptAll } from 'drizzle-orm/mysql-core'
    import { regularCustomerOrders, vipCustomerOrders } from './schema'

    const regularOrders = db.select({ 
        productId: regularCustomerOrders.productId,
        quantityOrdered: regularCustomerOrders.quantityOrdered }
    ).from(regularCustomerOrders);

    const vipOrders = db.select({ 
        productId: vipCustomerOrders.productId,
        quantityOrdered: vipCustomerOrders.quantityOrdered }
    ).from(vipCustomerOrders);

    const result = await exceptAll(regularOrders, vipOrders);
    ```
    ```sql
    (select `product_id`, `quantity_ordered` from `regular_customer_orders`)
    except all
    (select `product_id`, `quantity_ordered` from `vip_customer_orders`)
    ```
	</CodeTab>
    <CodeTab>
    ```ts copy
    import { regularCustomerOrders, vipCustomerOrders } from './schema'
 
    const result = await db
        .select({
          productId: regularCustomerOrders.productId,
          quantityOrdered: regularCustomerOrders.quantityOrdered,
        })
        .from(regularCustomerOrders)
        .exceptAll(
          db
            .select({
              productId: vipCustomerOrders.productId,
              quantityOrdered: vipCustomerOrders.quantityOrdered,
            })
            .from(vipCustomerOrders)
        );
    ```
    ```sql
    (select `product_id`, `quantity_ordered` from `regular_customer_orders`)
    except all
    (select `product_id`, `quantity_ordered` from `vip_customer_orders`)
    ```
    </CodeTab>
	<CodeTab>
	```typescript copy
	import { int, mysqlTable } from "drizzle-orm/mysql-core";

    export const regularCustomerOrders = mysqlTable('regular_customer_orders', {
        customerId: int('customer_id').primaryKey(),
        productId: int('product_id').notNull(),
        quantityOrdered: int('quantity_ordered').notNull(),
    });
    
    export const vipCustomerOrders = mysqlTable('vip_customer_orders', {
        customerId: int('customer_id').primaryKey(),
        productId: int('product_id').notNull(),
        quantityOrdered: int('quantity_ordered').notNull(),
    });
    ```
    </CodeTab>
  </CodeTabs>


Source: https://orm.drizzle.team/docs/mysql/sql-comments

import Section from '@mdx/Section.astro';
import Callout from '@mdx/Callout.astro';

# SQL Comments

You can add custom tags to any query using the `.comment()` method. These tags are appended as [sqlcommenter](https://google.github.io/sqlcommenter)-formatted comments at the end of each query, 
helping you attach metadata for query tracking, debugging and database traffic control.

The `.comment()` method is available on `select`, `insert`, `update` and `delete` queries.

### String comments
You can pass a raw string as a comment:

<Section>
```ts
db.select().from(users).comment("my_first_tag");
```
```sql
select `id`, `name` from `users` /*my_first_tag*/
```
</Section>

<Section>
```ts
db.select().from(users).comment("key='val'");
```
```sql
select `id`, `name` from `users` /*key='val'*/
```
</Section>

### Object comments
You can pass an object with key-value pairs for structured tags:

<Section>
```ts
db.select().from(users).comment({ priority: 'high', category: 'analytics' });
```
```sql
select `id`, `name` from `users` /*priority='high',category='analytics'*/
```
</Section>

<Section>
```ts
db.select().from(users).comment({ trace: true, route: '/api/users', version: 2 });
```
```sql
select `id`, `name` from `users` /*route='%2Fapi%2Fusers',trace='true',version='2'*/
```
</Section>

### Usage with insert, update, delete

<Section>
```ts
db.insert(users).values({ name: 'Dan' }).comment({ operation: 'seed' });
```
```sql
insert into `users` (`name`) values ('Dan') /*operation='seed'*/
```
</Section>

<Section>
```ts
db.update(users).set({ name: 'Dan' }).where(eq(users.id, 1)).comment({ operation: 'update' });
```
```sql
update `users` set `name` = 'Dan' where `users`.`id` = 1 /*operation='update'*/
```
</Section>

<Section>
```ts
db.delete(users).where(eq(users.id, 1)).comment({ operation: 'cleanup' });
```
```sql
delete from `users` where `users`.`id` = 1 /*operation='cleanup'*/
```
</Section>

### Limitations
You can't use `.comment()` after the statement has been prepared. Prepared statements compile the SQL query once and reuse it across executions, 
so the query string is fixed at preparation time and can't be modified afterwards — including appending comments:

```ts
// can't be used
const p = db.select().from(users).prepare();
// ❌
p.comment({ key: 'val' }).execute();
```

Instead, add the comment before preparing the statement:

```ts
// ✅
db.select().from(users).comment({ key: "val" }).prepare();
```

Source: https://orm.drizzle.team/docs/mysql/sql-schema-declaration

import Callout from '@mdx/Callout.astro';
import SimpleLinkCards from '@mdx/SimpleLinkCards.astro';
import CodeTabs from "@mdx/CodeTabs.astro";
import Section from '@mdx/Section.astro';
import Flex from "@mdx/Flex.astro"
import LinksList from "@mdx/LinksList.astro"

# Drizzle schema

Drizzle lets you define a schema in TypeScript with various models and properties supported by the underlying database. 
When you define your schema, it serves as the source of truth for future modifications in queries (using Drizzle-ORM)
and migrations (using Drizzle-Kit).

<Callout> 
If you are using Drizzle-Kit for the migration process, make sure to export all the models defined in your schema files so that Drizzle-Kit can import them and use them in the migration diff process. 
</Callout>

<CodeTabs items={["Using imports", "Using callback", "Using import *"]}>
```ts
import { int, mysqlTable, varchar } from "drizzle-orm/mysql-core";

export const usersTable = mysqlTable("users", {
  id: int().primaryKey().autoincrement(),
  name: varchar({ length: 256 }).notNull(),
  age: int().notNull(),
  email: varchar({ length: 256 }).notNull().unique(),
});
```
```ts
import { mysqlTable } from "drizzle-orm/mysql-core";

export const usersTable = mysqlTable("users", (t) => ({
  id: t.int().primaryKey().autoincrement(),
  name: t.varchar({ length: 256 }).notNull(),
  age: t.int().notNull(),
  email: t.varchar({ length: 256 }).notNull().unique(),
}));
```
```ts
import * as t from "drizzle-orm/mysql-core";

export const usersTable = t.mysqlTable("users", {
  id: t.int().primaryKey().autoincrement(),
  name: t.varchar({ length: 256 }).notNull(),
  age: t.int().notNull(),
  email: t.varchar({ length: 256 }).notNull().unique(),
});
```
</CodeTabs>

## Organize your schema files 
You can declare your SQL schema directly in TypeScript either in a single `schema.ts` file,
or you can spread them around — whichever you prefer, all the freedom!

#### Schema in 1 file
The most common way to declare your schema with Drizzle is to put all your tables into one `schema.ts` file.

> Note: You can name your schema file whatever you like. For example, it could be `models.ts`, or something else.

This approach works well if you don't have too many table models defined, or if you're okay with keeping them all in one file

Example:
```plaintext
📦 <project root>
 └ 📂 src
    └ 📂 db
       └ 📜 schema.ts
```

In the `drizzle.config.ts` file, you need to specify the path to your schema file. With this configuration, Drizzle will 
read from the `schema.ts` file and use this information during the migration generation process. For more information 
about the `drizzle.config.ts` file and migrations with Drizzle, please check: [link](/docs/mysql/drizzle-config-file)
```ts
import { defineConfig } from "drizzle-kit";

export default defineConfig({
  dialect: 'mysql',
  schema: './src/db/schema.ts'
})
```

#### Schema in multiple files

You can place your Drizzle models — such as tables, enums, sequences, etc. — not only in one file but in any file you prefer. 
The only thing you must ensure is that you export all the models from those files so that the Drizzle kit can import 
them and use them in migrations.

One use case would be to separate each table into its own file.
```plaintext
📦 <project root>
 └ 📂 src
    └ 📂 db
       └ 📂 schema
          ├ 📜 users.ts
          ├ 📜 countries.ts
          ├ 📜 cities.ts
          ├ 📜 products.ts
          ├ 📜 clients.ts
          └ 📜 etc.ts
```

In the `drizzle.config.ts` file, you need to specify the path to your schema folder. With this configuration, Drizzle will 
read from the `schema` folder and find all the files recursively and get all the drizzle tables from there. For more information 
about the `drizzle.config.ts` file and migrations with Drizzle, please check: [link](/docs/mysql/drizzle-config-file)

```ts
import { defineConfig } from "drizzle-kit";

export default defineConfig({
  dialect: 'mysql',
  schema: './src/db/schema'
})
```

You can also group them in any way you like, such as creating groups for user-related tables, messaging-related tables, product-related tables, etc. 
```plaintext
📦 <project root>
 └ 📂 src
    └ 📂 db
       └ 📂 schema
          ├ 📜 users.ts
          ├ 📜 messaging.ts
          └ 📜 products.ts
```

## Shape your data schema

Drizzle schema consists of several model types from database you are using. With drizzle you can specify:
- Tables with columns, constraints, etc.
- Schemas, which are equivalent to databases in MySQL
- Enums
- Views
- etc.

Let's go one by one and check how the schema should be defined with drizzle

#### **Tables and columns declaration** 

A table in Drizzle should be defined with at least 1 column, the same as it should be done in database. There is one important thing to know,
there is no such thing as a common table object in drizzle. You need to choose a dialect you are using, PostgreSQL, MySQL, SQLite, etc.

![](@/assets/images/table-structure.svg)

```ts copy
import { mysqlTable, int } from "drizzle-orm/mysql-core"

export const users = mysqlTable('users', {
  id: int()
});
```

By default, Drizzle will use the TypeScript key names for columns in database queries. 
Therefore, the schema and query from the example will generate the SQL query shown below

<Callout>
This example uses a db object, whose initialization is not covered in this part of the documentation. To learn how to connect to the database, please refer to the [Connections Docs](/docs/mysql/get-started-mysql)
</Callout>

\
**TypeScript key = database key**
<Section>
```ts
// schema.ts
import { int, mysqlTable, varchar } from "drizzle-orm/mysql-core";

export const users = mysqlTable('users', {
  id: int(),
  first_name: varchar({ length: 256 })
})
```
```ts
// query.ts
await db.select().from(users);
```
```sql
SELECT `id`, `first_name` FROM `users`;
```
</Section>

If you want to use different names in your TypeScript code and in the database, you can use column aliases

<Section>
```ts
// schema.ts
import { int, mysqlTable, varchar } from "drizzle-orm/mysql-core";

export const users = mysqlTable('users', {
  id: int(),
  firstName: varchar('first_name', { length: 256 })
})
```
```ts
// query.ts
await db.select().from(users);
```
```sql
SELECT `id`, `first_name` FROM `users`;
```
</Section>

### Camel and Snake casing

Database model names often use `snake_case` conventions, while in TypeScript, it is common to use `camelCase` for naming models. 
This can lead to a lot of alias definitions in the schema. To address this, Drizzle provides a way to automatically
map `camelCase` from TypeScript to `snake_case` in the database via a dedicated builder.

Use the `snakeCase` or `camelCase` builder from `drizzle-orm/pg-core` to declare a table whose column keys are
automatically mapped to the chosen database naming convention

<Section>
```ts {2,4,11,12}
// schema.ts
import { snakeCase, camelCase } from 'drizzle-orm/mysql-core';

export const users = snakeCase.table('users', {
  id: int().primaryKey().autoincrement(),
  fullName: text(), // → full_name in DB
  createdAt: timestamp(), // → created_at in DB
});

// Available on all entity types:
snakeCase.table / snakeCase.view / snakeCase.schema
camelCase.table / camelCase.view / camelCase.schema
```
```ts
// db.ts
import { drizzle } from "drizzle-orm/mysql2";

const db = drizzle({ connection: process.env.DATABASE_URL })
```
```ts
// query.ts
await db.select().from(users);
```
```sql
select `id`, `full_name`, `created_at` from `users`;
```
</Section>

### Advanced

There are a few tricks you can use with Drizzle ORM. As long as Drizzle is entirely in TypeScript files, 
you can essentially do anything you would in a simple TypeScript project with your code.

One common feature is to separate columns into different places and then reuse them. 
For example, consider the `updated_at`, `created_at`, and `deleted_at` columns. Many tables/models may need these 
three fields to track and analyze the creation, deletion, and updates of entities in a system

We can define those columns in a separate file and then import and spread them across all the table objects you have

<Section>
```ts
// columns.helpers.ts
export const timestamps = {
  updated_at: timestamp(),
  created_at: timestamp().defaultNow().notNull(),
  deleted_at: timestamp(),
}
```
```ts
// users.sql.ts
export const users = mysqlTable('users', {
  id: int(),
  ...timestamps
})
```
```ts
// posts.sql.ts
export const posts = mysqlTable('posts', {
  id: int(),
  ...timestamps
})
```
</Section>

#### **Schemas**


In MySQL, there is an entity called `Schema`, but in MySQL terms, this is equivalent to a `Database`. 

You can define them with `drizzle-orm` and use them in queries, but they won't be detected by `drizzle-kit` or included in the migration flow

![](@/assets/images/mysql-db-structure.png)

Define the schema you want to manage using Drizzle
```ts
import { mysqlSchema } from "drizzle-orm/mysql-core"

export const customSchema = mysqlSchema('custom');
```

Then place the table inside the schema object
```ts {5-7}
import { int, mysqlSchema } from "drizzle-orm/mysql-core";

export const customSchema = mysqlSchema('custom');

export const users = customSchema.table('users', {
  id: int()
})
```

### Example

Once you know the basics, let's define a schema example for a real project to get a better view and understanding

> All examples will use `generateUniqueString`. The implementation for it will be provided after all the schema examples

```ts copy
import { mysqlTable as table } from "drizzle-orm/mysql-core";
import * as t from "drizzle-orm/mysql-core";
import type { AnyMySqlColumn } from "drizzle-orm/mysql-core";

export const users = table(
  "users",
  {
    id: t.int().primaryKey().autoincrement(),
    firstName: t.varchar("first_name", { length: 256 }),
    lastName: t.varchar("last_name", { length: 256 }),
    email: t.varchar({ length: 256 }).notNull(),
    invitee: t.int().references((): AnyMySqlColumn => users.id),
    role: t.mysqlEnum(["guest", "user", "admin"]).default("guest"),
  },
  (table) => [
    t.uniqueIndex("email_idx").on(table.email)
  ]
);

export const posts = table(
  "posts",
  {
    id: t.int().primaryKey().autoincrement(),
    slug: t.varchar({ length: 256 }).$default(() => generateUniqueString(16)),
    title: t.varchar({ length: 256 }),
    ownerId: t.int("owner_id").references(() => users.id),
  },
  (table) => [
    t.uniqueIndex("slug_idx").on(table.slug),
    t.index("title_idx").on(table.title),
  ]
);

export const comments = table("comments", {
  id: t.int().primaryKey().autoincrement(),
  text: t.varchar({ length: 256 }),
  postId: t.int("post_id").references(() => posts.id),
  ownerId: t.int("owner_id").references(() => users.id),
});
```

**`generateUniqueString` implementation:**
```ts
function generateUniqueString(length: number = 12): string {
  const characters =
    "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
  let uniqueString = "";

  for (let i = 0; i < length; i++) {
    const randomIndex = Math.floor(Math.random() * characters.length);
    uniqueString += characters[randomIndex];
  }

  return uniqueString;
}
```

#### What's next?
<br/>
<Flex>
  <LinksList 
    title='Manage schema'
    links={[
        ["Column types", "/docs/mysql/column-types"], 
        ["Indexes and Constraints", "/docs/mysql/indexes-constraints"],
        ["Database Views", "/docs/mysql/views"],
        ["Database Schemas", "/docs/mysql/schemas"],
      ]}
  />
  <LinksList 
    title='Zero to Hero'
    links={[
        ["Database connection", "/docs/mysql/connect-overview"], 
        ["Data querying", "/docs/mysql/data-querying"], 
        ["Migrations", "/docs/mysql/migrations"], 
      ]}
  />
</Flex>


Source: https://orm.drizzle.team/docs/mysql/sql

import Callout from '@mdx/Callout.astro';
import Section from '@mdx/Section.astro';

# Magical `sql` operator 🪄

When working with an ORM library, there may be cases where you find it challenging to write a
specific query using the provided ORM syntax. In such situations, you can resort to using
raw queries, which involve constructing a query as a raw string. However, raw queries often
lack the benefits of type safety and query parameterization.

To address this, many libraries have introduced the concept of an `sql` template. This template 
allows you to write more type-safe and parameterized queries, enhancing the overall safety and 
flexibility of your code. Drizzle, being a powerful ORM library, also supports the sql template.

With Drizzle's `sql` template, you can go even further in crafting queries. If you encounter 
difficulties in writing an entire query using the library's query builder, you can selectively
use the `sql` template within specific sections of the Drizzle query. This flexibility enables you 
to employ the sql template in partial SELECT statements, WHERE clauses, ORDER BY clauses, HAVING
clauses, GROUP BY clauses, and even in relational query builders.

By leveraging the capabilities of the sql template in Drizzle, you can maintain the advantages 
of type safety and query parameterization while achieving the desired query structure and complexity.
This empowers you to create more robust and maintainable code within your application.

## sql`` template

One of the most common usages you may encounter in other ORMs as well 
is the ability to use `sql` queries as-is for raw queries.

```typescript copy
import { sql } from 'drizzle-orm' 

const id = 69;
await db.execute(sql`select * from ${usersTable} where ${usersTable.id} = ${id}`)
```

It will generate the current query

```sql
select * from `users` where `users`.`id` = ?; --> [69]
```

Any tables and columns provided to the sql parameter are automatically mapped to their corresponding SQL 
syntax with escaped names for tables, and the escaped table names are appended to column names. 

Additionally, any dynamic parameters such as `${id}` will be mapped to the `?` placeholder, 
and the corresponding values will be moved to an array of values that are passed separately to the database. 

This approach effectively prevents any potential SQL Injection vulnerabilities.

## `sql<T>`

<Callout type="info" emoji="ℹ️">
    Please note that `sql<T>` does not perform any runtime mapping. The type you define using `sql<T>` is
    purely a helper for Drizzle. It is important to understand that there is no feasible way to 
    determine the exact type dynamically, as SQL queries can be highly versatile and customizable. 
</Callout>

You can define a custom type in Drizzle to be used in places where fields require a specific type other than `unknown`.

This feature is particularly useful in partial select queries, ensuring consistent typing for selected fields:

```typescript
// without sql<T> type defined
const response: { lowerName: unknown }[] = await db.select({
    lowerName: sql`lower(${usersTable.id})`
}).from(usersTable);

// with sql<T> type defined
const response: { lowerName: string }[] = await db.select({
    lowerName: sql<string>`lower(${usersTable.id})`
}).from(usersTable);
```

## `sql``.mapWith()`

For the cases you need to make a runtime mapping for values passed from database driver to drizzle you can use `.mapWith()`

This function accepts different values, that will map response in runtime.

You can replicate a specific column mapping strategy as long as
the interface inside mapWith is the same interface that is implemented by Column.

```typescript
import { mysqlTable, int, text } from 'drizzle-orm/mysql-core';

const usersTable = mysqlTable('users', {
    id: int().primaryKey().autoincrement(),
    name: text().notNull(),
});

//  at runtime this values will be mapped same as `text` column is mapped in drizzle
sql`...`.mapWith(usersTable.name);
```

You can also pass your own implementation for the `DriverValueDecoder` interface:

```ts 
sql``.mapWith({
	mapFromDriverValue: (value: any) => {
		const mappedValue = value;
		// mapping you want to apply
		return mappedValue;
	},
});
    
// or
sql``.mapWith(Number);
```

## `sql``.as<T>()`

In different cases, it can sometimes be challenging to determine how to name a custom field that you want to use.
You may encounter situations where you need to explicitly specify an alias for a 
field that will be selected. This can be particularly useful when dealing with complex queries. 

To address these scenarios, we have introduced a helpful `.as('alias_name')` helper, which allows 
you to define an alias explicitly. By utilizing this feature, you can provide a clear and meaningful 
name for the field, making your queries more intuitive and readable.

<Section>
```typescript
sql`lower(${usersTable.name})`.as('lower_name')
```
```sql
... `users`.`name` as lower_name ...
```
</Section>

## `sql.raw()`

There are cases where you may not need to create parameterized values from input or map tables/columns to escaped ones. 
Instead, you might simply want to generate queries as they are. For such situations, we provide the `sql.raw()` function.

The `sql.raw()` function allows you to include raw SQL statements within your queries without any additional processing or escaping.
This can be useful when you have pre-constructed SQL statements or when you need to incorporate complex or dynamic 
SQL code directly into your queries.

<Section>
```typescript
sql.raw(`select * from users where id = ${12}`);
// vs
sql`select * from users where id = ${12}`;
```
```sql
select * from users where id = 12;
--> vs
select * from users where id = ?; --> [12]
```
</Section>

You can also utilize `sql.raw()` within the sql function, enabling you to include any raw string
without escaping it through the main `sql` template function.

By using `sql.raw()` inside the `sql` function, you can incorporate unescaped raw strings 
directly into your queries. This can be particularly useful when you have specific
SQL code or expressions that should remain untouched by the template function's automatic escaping or modification.

<Section>
```typescript
sql`select * from ${usersTable} where id = ${12}`;
// vs
sql`select * from ${usersTable} where id = ${sql.raw(12)}`;
```
```sql
select * from `users` where id = ?; --> [12]
--> vs
select * from `users` where id = 12;
```
</Section>

## sql.fromList()

The `sql` template generates sql chunks, which are arrays of SQL parts that will be concatenated 
into the query and params after applying the SQL to the database or query in Drizzle.

In certain scenarios, you may need to aggregate these chunks into an array using custom business 
logic and then concatenate them into a single SQL statement that can be passed to the database or query.
For such cases, the fromList function can be quite useful.

The fromList function allows you to combine multiple SQL chunks into a single SQL statement. 
You can use it to aggregate and concatenate the individual SQL parts according to your specific 
requirements and then obtain a unified SQL query that can be executed.

<Section>
```typescript
const sqlChunks: SQL[] = [];

sqlChunks.push(sql`select * from users`);

// some logic

sqlChunks.push(sql` where `);

// some logic

for (let i = 0; i < 5; i++) {
	sqlChunks.push(sql`id = ${i}`);

	if (i === 4) continue;
	sqlChunks.push(sql` or `);
}

const finalSql: SQL = sql.fromList(sqlChunks)
```
```sql
select * from users where id = ? or id = ? or id = ? or id = ? or id = ?; --> [0, 1, 2, 3, 4]
```
</Section>

## sql.join()

Indeed, the `sql.join` function serves a similar purpose to the fromList helper. 
However, it provides additional flexibility when it comes to handling spaces between
SQL chunks or specifying custom separators for concatenating the SQL chunks.

With `sql.join`, you can concatenate SQL chunks together using a specified separator. 
This separator can be any string or character that you want to insert between the chunks. 

This is particularly useful when you have specific requirements for formatting or delimiting 
the SQL chunks. By specifying a custom separator, you can achieve the desired structure and formatting 
in the final SQL query.

<Section>
```typescript
const sqlChunks: SQL[] = [];

sqlChunks.push(sql`select * from users`);

// some logic

sqlChunks.push(sql`where`);

// some logic

for (let i = 0; i < 5; i++) {
	sqlChunks.push(sql`id = ${i}`);

if (i === 4) continue;
    sqlChunks.push(sql`or`);
}

const finalSql: SQL = sql.join(sqlChunks, sql.raw(' '));
```
```sql
select * from users where id = ? or id = ? or id = ? or id = ? or id = ?; --> [0, 1, 2, 3, 4]
```
</Section>

## sql.append()

If you have already generated SQL using the `sql` template, you can achieve the same behavior as `fromList`
by using the append function to directly add a new chunk to the generated SQL.

By using the append function, you can dynamically add additional SQL chunks to the existing SQL string,
effectively concatenating them together. This allows you to incorporate custom logic or business 
rules for aggregating the chunks into the final SQL query.

<Section>
```typescript 
const finalSql = sql`select * from users`;

// some logic

finalSql.append(sql` where `);

// some logic

for (let i = 0; i < 5; i++) {
	finalSql.append(sql`id = ${i}`);

	if (i === 4) continue;
	finalSql.append(sql` or `);
}
```
```sql
select * from users where id = ? or id = ? or id = ? or id = ? or id = ?; --> [0, 1, 2, 3, 4]
```
</Section>

## sql.empty()

By using sql.empty(), you can start with a blank SQL object and then dynamically append SQL chunks to it as needed. This allows you to construct the SQL query incrementally, applying custom logic or conditions to determine the contents of each chunk.

Once you have initialized the SQL object using sql.empty(), you can take advantage of the full range
of sql template features such as parameterization, composition, and escaping. 
This empowers you to construct the SQL query in a flexible and controlled manner, 
adapting it to your specific requirements.

```typescript 
const finalSql = sql.empty();

// some logic

finalSql.append(sql`select * from users`);

// some logic

finalSql.append(sql` where `);

// some logic

for (let i = 0; i < 5; i++) {
	finalSql.append(sql`id = ${i}`);

	if (i === 4) continue;
	finalSql.append(sql` or `);
}
```
```sql
select * from users where id = ? or id = ? or id = ? or id = ? or id = ?; --> [0, 1, 2, 3, 4]
```

## Convert `sql` to string and params

In all the previous examples, you observed the usage of SQL template syntax in TypeScript along with 
the generated SQL output.

If you need to obtain the query string and corresponding parameters generated from the SQL template, 
you must specify the database dialect you intend to generate the query for. Different databases have
varying syntax for parameterization and escaping, so selecting the appropriate dialect is crucial.

Once you have chosen the dialect, you can utilize the corresponding implementation's functionality
to convert the SQL template into the desired query string and parameter format. This ensures 
compatibility with the specific database system you are working with.

<Section>
```typescript copy
import { MySqlDialect } from 'drizzle-orm/mysql-core';

const mysqlDialect = new MySqlDialect();
mysqlDialect.sqlToQuery(sql`select * from ${usersTable} where ${usersTable.id} = ${12}`);
```
```sql
select * from `users` where `users`.`id` = ?; --> [ 12 ]
```
</Section>

## `sql` select

You can use the sql functionality in partial select queries as well. Partial select queries allow you to 
retrieve specific fields or columns from a table rather than fetching the entire row.

For more detailed information about partial select queries, you can refer to the Core API
documentation available at **[Core API docs](/docs/mysql/select#basic-and-partial-select)**.

**Select different custom fields from table**

Here you can see a usage for **[`sql<T>`](/docs/mysql/sql#sqlt)**, **[`sql``.mapWith()`](/docs/mysql/sql#sqlmapwith)**, **[`sql``.as<T>()`](/docs/mysql/sql#sqlast)**.

<Section>
```typescript copy
import { sql } from 'drizzle-orm'
import { usersTable } from 'schema'

await db.select({
    id: usersTable.id,
    lowerName: sql<string>`lower(${usersTable.name})`,
    aliasedName: sql<string>`lower(${usersTable.name})`.as('aliased_column'),
    count: sql<number>`count(*)`.mapWith(Number) 
}).from(usersTable)
```
```sql
select `id`, lower(`name`), lower(`name`) as `aliased_column`, count(*) from `users`;
```
</Section>

## `sql` in where

Indeed, Drizzle provides a set of available expressions that you can use within the sql template. 
However, it is true that databases often have a wider range of expressions available, 
including those provided through extensions or other means.

To ensure flexibility and enable you to utilize any expressions that are not natively
supported by Drizzle, you have the freedom to write the SQL template
directly using the sql function. This allows you to leverage the full power of
SQL and incorporate any expressions or functionalities specific to your target database.

By using the sql template, you are not restricted to only the predefined expressions in Drizzle. 
Instead, you can express complex queries and incorporate any supported expressions that 
the underlying database system provides.

**Filtering by `id` but with sql**
<Section>
```typescript copy
import { sql } from 'drizzle-orm'
import { usersTable } from 'schema'

const id = 77

await db.select()
        .from(usersTable)
        .where(sql`${usersTable.id} = ${id}`)
```
```sql
select * from `users` where `users`.`id` = ?; --> [ 77 ]
```
</Section>

**Advanced fulltext search where statement**
<Section>
```typescript copy
import { sql } from 'drizzle-orm'
import { usersTable } from 'schema'

const searchPattern = "%Ale%"

await db.select()
        .from(usersTable)
        .where(sql`lower(${usersTable.name}) like lower(${searchPattern})`)
```
```sql
select * from `users` where lower(`users`.`name`) like lower(?); --> [ "%Ale%" ]
```
</Section>

## `sql` in orderBy

The `sql` template can indeed be used in the ORDER BY clause when you need specific functionality for ordering that is not
available in Drizzle, but you prefer not to resort to raw SQL.

<Section>
```typescript copy
import { sql } from 'drizzle-orm'
import { usersTable } from 'schema'

await db.select().from(usersTable).orderBy(sql`${usersTable.id} desc nulls first`)
```
```sql
select * from `users` order by `users`.`id` desc nulls first;
```
</Section>

## `sql` in having and groupBy

The `sql` template can indeed be used in the HAVING and GROUP BY clauses when you need specific functionality for ordering that is not
available in Drizzle, but you prefer not to resort to raw SQL.

<Section>
```typescript copy
import { sql } from 'drizzle-orm'
import { usersTable } from 'schema'

await db.select({ 
    projectId: usersTable.projectId,
    count: sql<number>`count(${usersTable.id})`.mapWith(Number)
}).from(usersTable)
    .groupBy(sql`${usersTable.projectId}`)
    .having(sql`count(${usersTable.id}) > 300`)
```
```sql
select `project_id`, count(`users`.`id`) from users group by `users`.`project_id` having count(`users`.`id`) > 300; 
```
</Section>


Source: https://orm.drizzle.team/docs/mysql/transactions

# Transactions

SQL transaction is a grouping of one or more SQL statements that interact with a database.
A transaction in its entirety can commit to a database as a single logical unit
or rollback (become undone) as a single logical unit.

Drizzle ORM provides APIs to run SQL statements in transactions:

```ts copy
const db = drizzle(...)

await db.transaction(async (tx) => {
  await tx.update(accounts).set({ balance: sql`${accounts.balance} - 100.00` }).where(eq(users.name, 'Dan'));
  await tx.update(accounts).set({ balance: sql`${accounts.balance} + 100.00` }).where(eq(users.name, 'Andrew'));
});
```

Drizzle ORM supports `savepoints` with nested transactions API:

```ts copy {7-9}
const db = drizzle(...)

await db.transaction(async (tx) => {
  await tx.update(accounts).set({ balance: sql`${accounts.balance} - 100.00` }).where(eq(users.name, 'Dan'));
  await tx.update(accounts).set({ balance: sql`${accounts.balance} + 100.00` }).where(eq(users.name, 'Andrew'));

  await tx.transaction(async (tx2) => {
    await tx2.update(users).set({ name: "Mr. Dan" }).where(eq(users.name, "Dan"));
  });
});
```

You can embed business logic to the transaction and rollback whenever needed:

```ts copy {7}
const db = drizzle(...)

await db.transaction(async (tx) => {
  const [account] = await tx.select({ balance: accounts.balance }).from(accounts).where(eq(users.name, 'Dan'));
  if (account.balance < 100) {
    // This throws an exception that rollbacks the transaction.
    tx.rollback()
  }

  await tx.update(accounts).set({ balance: sql`${accounts.balance} - 100.00` }).where(eq(users.name, 'Dan'));
  await tx.update(accounts).set({ balance: sql`${accounts.balance} + 100.00` }).where(eq(users.name, 'Andrew'));
});
```

You can return values from the transaction:

```ts copy {8}
const db = drizzle(...)

const newBalance: number = await db.transaction(async (tx) => {
  await tx.update(accounts).set({ balance: sql`${accounts.balance} - 100.00` }).where(eq(users.name, 'Dan'));
  await tx.update(accounts).set({ balance: sql`${accounts.balance} + 100.00` }).where(eq(users.name, 'Andrew'));

  const [account] = await tx.select({ balance: accounts.balance }).from(accounts).where(eq(users.name, 'Dan'));
  return account.balance;
});
```

You can use transactions with **[relational queries](/docs/mysql/rqb)**:

```ts
const db = drizzle({ schema })

await db.transaction(async (tx) => {
  await tx.query.users.findMany({
    with: {
      accounts: true
    }
  });
});
```

We provide dialect-specific transaction configuration APIs:

```ts {6-8}
await db.transaction(
  async (tx) => {
    await tx.update(accounts).set({ balance: sql`${accounts.balance} - 100.00` }).where(eq(users.name, "Dan"));
    await tx.update(accounts).set({ balance: sql`${accounts.balance} + 100.00` }).where(eq(users.name, "Andrew"));
  }, {
    isolationLevel: "read committed",
    accessMode: "read write",
    withConsistentSnapshot: true,
  }
);

interface MySqlTransactionConfig {
  isolationLevel?:
    | "read uncommitted"
    | "read committed"
    | "repeatable read"
    | "serializable";
  accessMode?: "read only" | "read write";
  withConsistentSnapshot?: boolean;
}
```


Source: https://orm.drizzle.team/docs/mysql/typebox-legacy

import Npm from '@mdx/Npm.astro';
import Callout from '@mdx/Callout.astro';

# typebox-legacy

### Install the dependencies
<Npm>
drizzle-orm@rc @sinclair/typebox
</Npm>

### Select schema

Defines the shape of data queried from the database - can be used to validate API responses.

```ts copy
import { int, mysqlTable, text } from 'drizzle-orm/mysql-core';
import { createSelectSchema } from 'drizzle-orm/typebox-legacy';
import { Value } from '@sinclair/typebox/value';

const users = mysqlTable('users', {
  id: int().primaryKey().autoincrement(),
  name: text().notNull(),
  age: int().notNull()
});

const userSelectSchema = createSelectSchema(users);

const rows = await db.select({ id: users.id, name: users.name }).from(users).limit(1);
const parsed: { id: number; name: string; age: number } = Value.Parse(userSelectSchema, rows[0]); // Error: `age` is not returned in the above query

const rows = await db.select().from(users).limit(1);
const parsed: { id: number; name: string; age: number } = Value.Parse(userSelectSchema, rows[0]); // Will parse successfully
```

Views are also supported.

```ts copy
import { mysqlView } from 'drizzle-orm/mysql-core';
import { gt } from 'drizzle-orm';
import { createSelectSchema } from 'drizzle-orm/typebox-legacy';
import { Value } from '@sinclair/typebox/value';

const usersView = mysqlView('users_view').as((qb) => qb.select().from(users).where(gt(users.age, 18)));
const usersViewSchema = createSelectSchema(usersView);
const parsed: { id: number; name: string; age: number } = Value.Parse(usersViewSchema, ...);
```

### Insert schema

Defines the shape of data to be inserted into the database - can be used to validate API requests.

```ts copy
import { int, mysqlTable, text } from 'drizzle-orm/mysql-core';
import { createInsertSchema } from 'drizzle-orm/typebox-legacy';
import { Value } from '@sinclair/typebox/value';

const users = mysqlTable('users', {
  id: int().primaryKey().autoincrement(),
  name: text().notNull(),
  age: int().notNull()
});

const userInsertSchema = createInsertSchema(users);

const user = { name: 'John' };
const parsed: { id?: number | undefined, name: string, age: number } = Value.Parse(userInsertSchema, user); // Error: `age` is not defined

const user = { name: 'Jane', age: 30 };
const parsed: { id?: number | undefined, name: string, age: number } = Value.Parse(userInsertSchema, user); // Will parse successfully
await db.insert(users).values(parsed);
```

### Update schema

Defines the shape of data to be updated in the database - can be used to validate API requests.

```ts copy
import { int, mysqlTable, text } from 'drizzle-orm/mysql-core';
import { createUpdateSchema } from 'drizzle-orm/typebox-legacy';
import { Value } from '@sinclair/typebox/value';
import { eq } from "drizzle-orm";

const users = mysqlTable('users', {
  id: int().primaryKey().autoincrement(),
  name: text().notNull(),
  age: int().notNull()
});

const userUpdateSchema = createUpdateSchema(users);

const user = { age: 35 };
const parsed: { id?: number | undefined, name?: string | undefined, age?: number | undefined } = Value.Parse(userUpdateSchema, user); // Will parse successfully
await db.update(users).set(parsed).where(eq(users.name, 'Jane'));
```

### Refinements

Each create schema function accepts an additional optional parameter that you can used to extend, modify or completely overwite a field's schema. Defining a callback function will extend or modify while providing a Typebox schema will overwrite it.

```ts copy
import { int, json, mysqlTable, text } from 'drizzle-orm/mysql-core';
import { createSelectSchema } from 'drizzle-orm/typebox-legacy';
import { Type } from '@sinclair/typebox';
import { Value } from '@sinclair/typebox/value';

const users = mysqlTable('users', {
  id: int().primaryKey().autoincrement(),
  name: text().notNull(),
  bio: text(),
  preferences: json()
});

const userSelectSchema = createSelectSchema(users, {
  name: (schema) => Type.String({ ...schema, maxLength: 20 }), // Extends schema
  bio: (schema) => Type.String({ ...schema, maxLength: 1000 }), // Extends schema before becoming nullable/optional
  preferences: Type.Object({ theme: Type.String() }) // Overwrites the field, including its nullability
});

const parsed: {
  id: number;
  name: string,
  bio: string | null;
  preferences: {
    theme: string;
  };
} = Value.Parse(userSelectSchema, ...);
```

### Factory functions

For more advanced use cases, you can use the `createSchemaFactory` function.

**Use case: Using an extended Typebox instance**

```ts copy
import { int, mysqlTable, text } from 'drizzle-orm/mysql-core';
import { createSchemaFactory } from 'drizzle-orm/typebox';
import { t } from 'elysia'; // Extended Typebox instance

const users = mysqlTable('users', {
  id: int().primaryKey().autoincrement(),
  name: text().notNull(),
  age: int().notNull()
});

const { createInsertSchema } = createSchemaFactory({ typeboxInstance: t });

const userInsertSchema = createInsertSchema(users, {
  // We can now use the extended instance
  name: (schema) => t.Number({ ...schema, error: "`name` must be a string" })
});
```

### Data type reference

```ts
mysql.boolean();

// Schema
Type.Boolean();
```

```ts
mysql.mysqlEnum('name', ['val1', 'val2']);

// Schema
Type.Enum({ 'val1': 'val1', 'val2': 'val2' });
```

```ts
mysql.date({ mode: 'date' });
mysql.datetime({ mode: 'date' });
mysql.timestamp({ mode: 'date' });

// Schema
Type.Date();
```

```ts
mysql.binary();
mysql.date({ mode: 'string' });
mysql.datetime({ mode: 'string' });
mysql.decimal();
mysql.time();
mysql.timestamp({ mode: 'string' });
mysql.varbinary();

// Schema
Type.String();
```

```ts
mysql.tinyblob({ mode: 'string' });
mysql.tinyblob();

Type.String({ maxLength: 255 })
```

```ts
mysql.blob({ mode: 'string' });
mysql.blob();

Type.String({ maxLength: 65_535 })
```

```ts
mysql.mediumblob({ mode: 'string' });
mysql.mediumblob();

Type.String({ maxLength: 16_777_215 })
```

```ts
mysql.longblob({ mode: 'string' });
mysql.longblob();

Type.String({ maxLength: 4_294_967_295 })
```

```ts
mysql.char({ length: ... });

// Schema
Type.String({ minLength: length, maxLength: length });
```

```ts
mysql.varchar({ length: ... });

// Schema
Type.String({ maxLength: length });
```

```ts
binary({ length: ... });

// Schema
Type.RegExp(/^[01]*$/, { maxLength: length })
```

```ts
mysql.varbinary({ length: ... });

// Schema
Type.RegExp(/^[01]*$/, { maxLength: length })
```

```ts
mysql.tinytext();

// Schema
Type.String({ maxLength: 255 }); // unsigned 8-bit integer limit
```

```ts
mysql.text();

// Schema
Type.String({ maxLength: 65_535 }); // unsigned 16-bit integer limit
```

```ts
mysql.mediumtext();

// Schema
Type.String({ maxLength: 16_777_215 }); // unsigned 24-bit integer limit
```

```ts
mysql.longtext();

// Schema
Type.String({ maxLength: 4_294_967_295 }); // unsigned 32-bit integer limit
```

```ts
mysql.tinytext({ enum: ... });
mysql.mediumtext({ enum: ... });
mysql.text({ enum: ... });
mysql.longtext({ enum: ... });
mysql.char({ enum: ... });
mysql.varchar({ enum: ... });

// Schema
Type.Enum(enum);
```

```ts
mysql.tinyint();

// Schema
Type.Integer({ minimum: -128, maximum: 127 }); // 8-bit integer lower and upper limit
```

```ts
mysql.tinyint({ unsigned: true });

// Schema
Type.Integer({ minimum: 0, maximum: 255 }); // unsigned 8-bit integer lower and upper limit
```

```ts
mysql.smallint();

// Schema
Type.Integer({ minimum: -32_768, maximum: 32_767 }); // 16-bit integer lower and upper limit
```

```ts
mysql.smallint({ unsigned: true });

// Schema
Type.Integer({ minimum: 0, maximum: 65_535 }); // unsigned 16-bit integer lower and upper limit
```

```ts
mysql.float();

// Schema
Type.Number().min(-8_388_608).max(8_388_607); // 24-bit integer lower and upper limit
```

```ts
mysql.mediumint();

// Schema
Type.Integer({ minimum: -8_388_608, maximum: 8_388_607 }); // 24-bit integer lower and upper limit
```

```ts
mysql.float({ unsigned: true });

// Schema
Type.Number({ minimum: 0, maximum: 16_777_215 }); // unsigned 24-bit integer lower and upper limit
```

```ts
mysql.mediumint({ unsigned: true });

// Schema
Type.Integer({ minimum: 0, maximum: 16_777_215 }); // unsigned 24-bit integer lower and upper limit
```

```ts
mysql.int();

// Schema
Type.Integer({ minimum: -2_147_483_648, maximum: 2_147_483_647 }); // 32-bit integer lower and upper limit
```

```ts
mysql.int({ unsigned: true });

// Schema
Type.Integer({ minimum: 0, maximum: 4_294_967_295 }); // unsgined 32-bit integer lower and upper limit
```

```ts
mysql.double();
mysql.real();

// Schema
Type.Number({ minimum: -140_737_488_355_328, maximum: 140_737_488_355_327 }); // 48-bit integer lower and upper limit
```

```ts
mysql.double({ unsigned: true });

// Schema
Type.Numer({ minimum: 0, maximum: 281_474_976_710_655 }); // unsigned 48-bit integer lower and upper limit
```

```ts
mysql.decimal({ mode: 'number' });

// Schema
Type.Number({ minimum: -9_007_199_254_740_991, maximum: 9_007_199_254_740_991 });
```

```ts
mysql.decimal({ mode: 'bigint' });

// Schema
Type.BigInt({ minimum: -9_223_372_036_854_775_808n, maximum: 9_223_372_036_854_775_807n });
```

```ts
mysql.decimal({ mode: 'number', unsigned: true });

// Schema
Type.Number({ minimum: 0, maximum: 9_007_199_254_740_991 });
```

```ts
mysql.decimal({ mode: 'bigint', unsigned: true });

// Schema
Type.BigInt({ minimum: 0, maximum: 18_446_744_073_709_551_615n });
```

```ts
mysql.bigint({ mode: 'number' });

// Schema
Type.Integer({ minimum: -9_007_199_254_740_991, maximum: 9_007_199_254_740_991 }); // Javascript min. and max. safe integers
```

```ts
mysql.bigint({ mode: 'number', unsigned: true });

// Schema
Type.Integer({ minimum: 0, maximum: 9_007_199_254_740_991 }); // Javascript min. and max. safe integers
```

```ts
mysql.bigint({ mode: 'string' });

// Schema
TypeRegistry.Set('BigIntStringMode', (_, value) => {
	if (typeof value !== 'string' || !(/^-?\d+$/.test(value))) {
		return false;
	}

	const bigint = BigInt(value);
	if (bigint < -9_223_372_036_854_775_808n || bigint > 9_223_372_036_854_775_807n) {
		return false;
	}

	return true;
});

{ [Kind]: 'BigIntStringMode', type: 'string' }
```

```ts
mysql.bigint({ mode: 'string', unsigned: true });

// Schema
TypeRegistry.Set('UnsignedBigIntStringMode', (_, value) => {
	if (typeof value !== 'string' || !(/^\d+$/.test(value))) {
		return false;
	}

	const bigint = BigInt(value);
	if (bigint < 0 || bigint > 9_223_372_036_854_775_807n) {
		return false;
	}

	return true;
});

{ [Kind]: 'UnsignedBigIntStringMode', type: 'string' }
```

```ts
mysql.bigint({ mode: 'bigint' });

// Schema
Type.BigInt({ minimum: -9_223_372_036_854_775_808n, maximum: 9_223_372_036_854_775_807n }); // 64-bit integer lower and upper limit
```

```ts
mysql.bigint({ mode: 'bigint', unsigned: true });

// Schema
Type.BigInt({ minimum: 0, maximum: 18_446_744_073_709_551_615n }); // unsigned 64-bit integer lower and upper limit
```

```ts
mysql.serial();

Type.Integer({ minimum: 0, maximum: 9_007_199_254_740_991 })
```

```ts
mysql.year();

// Schema
Type.Integer({ minimum: 1_901, maximum: 2_155 });
```

```ts
mysql.json();

// Schema
Type.Recursive((self) => Type.Union([Type.Union([Type.String(), Type.Number(), Type.Boolean(), Type.Null()]), Type.Array(self), Type.Record(Type.String(), self)]));
```


Source: https://orm.drizzle.team/docs/mysql/typebox

import Npm from '@mdx/Npm.astro';
import Callout from '@mdx/Callout.astro';

# typebox

#### Install the dependencies
<Npm>
drizzle-orm@rc typebox
</Npm>

Allows you to generate [typebox](https://sinclairzx81.github.io/typebox/#/) schemas from Drizzle ORM schemas

**Features**

- Create a select schema for tables and views.
- Create insert and update schemas for tables.

#### Usage

```ts
import { int, mysqlTable, text, timestamp } from 'drizzle-orm/mysql-core';
import { createInsertSchema, createSelectSchema, createUpdateSchema } from 'drizzle-orm/typebox';
import { Type } from 'typebox';
import { Value } from 'typebox/value';

const users = mysqlTable('users', {
	id: int().primaryKey().autoincrement(),
	name: text().notNull(),
	email: text().notNull(),
	role: text({ enum: ['admin', 'user'] }).notNull(),
	createdAt: timestamp('created_at').notNull().defaultNow(),
});

// Schema for inserting a user - can be used to validate API requests
const insertUserSchema = createInsertSchema(users);

// Schema for updating a user - can be used to validate API requests
const updateUserSchema = createUpdateSchema(users);

// Schema for selecting a user - can be used to validate API responses
const selectUserSchema = createSelectSchema(users);

// Overriding the fields
const insertUserSchema = createInsertSchema(users, {
	role: Type.String(),
});

// Refining the fields - useful if you want to change the fields before they become nullable/optional in the final schema
const insertUserSchema = createInsertSchema(users, {
	id: (schema) => Type.Number({ ...schema, minimum: 0 }),
	role: Type.String(),
});

// Usage
const isUserValid: boolean = Value.Check(insertUserSchema, {
	name: 'John Doe',
	email: 'johndoe@test.com',
	role: 'admin',
});
```


Source: https://orm.drizzle.team/docs/mysql/update

import Callout from '@mdx/Callout.astro';
import Section from '@mdx/Section.astro';

# SQL Update

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

The object that you pass to `update` should have keys that match column names in your database schema.
Values of `undefined` are ignored in the object: to set a column to `null`, pass `null`.
You can pass SQL as a value to be used in the update object, like this:

```typescript copy
await db.update(users)
  .set({ updatedAt: sql`NOW()` })
  .where(eq(users.name, 'Dan'));
```

### Limit
Use `.limit()` to add `limit` clause to the query - for example:
<Section>
```typescript
await db.update(usersTable).set({ verified: true }).limit(2);
```
```sql
update `users` set `verified` = true limit 2
```
</Section>

### Order By
Use `.orderBy()` to add `order by` clause to the query, sorting the results by the specified fields:
<Section>
```typescript
import { asc, desc } from 'drizzle-orm';

await db.update(usersTable).set({ verified: true }).orderBy(usersTable.name);
await db.update(usersTable).set({ verified: true }).orderBy(desc(usersTable.name));

// order by multiple fields
await db.update(usersTable).set({ verified: true }).orderBy(usersTable.name, usersTable.name2);
await db.update(usersTable).set({ verified: true }).orderBy(asc(usersTable.name), desc(usersTable.name2));
```
```sql
update `users` set `verified` = true order by `users`.`name`;
update `users` set `verified` = true order by `users`.`name` desc;

update `users` set `verified` = true order by `users`.`name`, `users`.`name2`;
update `users` set `verified` = true order by `users`.`name` asc, `users`.`name2` desc;
```
</Section>



Source: https://orm.drizzle.team/docs/mysql/upgrade-v1

import Npm from "@mdx/Npm.astro";
import Npx from "@mdx/Npx.astro";
import Prerequisites from "@mdx/Prerequisites.astro";

# Upgrading to Drizzle v1

<Npm>
 drizzle-orm@rc
 -D drizzle-kit@rc
</Npm>

#### Step 1 - Run `drizzle-kit up`

> v3 migration folder discussion: https://github.com/drizzle-team/drizzle-orm/discussions/2832  

We've updated the migrations folder structure by:
- removing `journal.json`
- grouping SQL files and snapshots into separate migration folders
- removing the `drizzle-kit drop` command

These changes eliminate potential Git conflicts with the journal file and simplify the process of dropping or fixing conflicted migrations

The drizzle-kit has been architecturally redesigned:
- Migrated from database snapshots to DDL snapshots

Commutativity checks were added:
- Detecting non-commutative migrations across branches
> Commutativity discussion: https://github.com/drizzle-team/drizzle-orm/discussions/5005

To migrate from old structure to a new one you would need to run

<Npx>
drizzle-kit up
</Npx>

#### Step 2 - Review breaking changes

You can find out the full list of breaking changes [here](/docs/mysql/v0-v1-changes#breaking-changes) and make sure to update your code accordingly

If you were using Relational Queries, you need to upgrade to v2:
- [How to migrate relations definition from v1 to v2](/docs/mysql/relations-v1-v2#how-to-migrate-relations-schema-definition-from-v1-to-v2)
- [How to migrate queries from v1 to v2](/docs/mysql/relations-v1-v2#how-to-migrate-queries-from-v1-to-v2)

#### Step 3 - Done ✅


Source: https://orm.drizzle.team/docs/mysql/v0-v1-changes

import Callout from '@mdx/Callout.astro';

# Changes in v1

This page shows everything that changed from `drizzle-orm@0.x`, `drizzle-kit@0.x`, `drizzle-seed@0.x` to the latest `drizzle-orm@1.0`, `drizzle-kit@1.0`, `drizzle-seed@1.0`

<Callout type="info">
Read more on how to upgrade [here](/docs/mysql/upgrade-v1)
</Callout>

## Breaking changes

#### Relational Queries v1 removed

RQBv1 has been removed. Use [Relational Queries v2](/docs/mysql/relations) with the new `defineRelations()` API instead and new features. You can find more details about migrating from rqb v1 to v2 [here](/docs/mysql/relations-v1-v2)

A new relations system built around `defineRelations()`:

```ts
import { defineRelations } from 'drizzle-orm';

const relations = defineRelations(schema, (r) => ({
  users: {
    posts: r.many.posts(),
    profile: r.one.profiles(),
  },
  posts: {
    author: r.one.users({
      from: posts.authorId,
      to: users.id,
    }),
  },
}));
```

#### Validator packages consolidated into `drizzle-orm`

<Callout type="warning">
You can still use drizzle-zod/valibot/typebox/arktype validation packages but all new update will be added to Drizzle ORM directly
</Callout>

- drizzle-zod -> drizzle-orm/zod
- drizzle-valibot -> drizzle-orm/valibot
- drizzle-typebox -> drizzle-orm/typebox-legacy (using @sinclair/typebox)
- drizzle-typebox -> drizzle-orm/typebox (using typebox)
- drizzle-arktype -> drizzle-orm/arktype
- new `drizzle-orm/effect-schema` package added

#### New Casing API

The legacy `drizzle({ casing: 'camelCase' })` has been replaced with a table/view/schema-level API:

```ts
import { snakeCase, camelCase } from 'drizzle-orm/mysql-core';

export const users = snakeCase.table('users', {
  id: int().primaryKey().autoincrement(),
  fullName: text(),       // → full_name in DB
  createdAt: timestamp(), // → created_at in DB
});

// Available on all entity types:
snakeCase.table / snakeCase.view / snakeCase.materializedView / snakeCase.schema
camelCase.table / camelCase.view / camelCase.materializedView / camelCase.schema
```

#### `.generatedAlwaysAs()` only accepts SQL

```ts
// ❌ Before — accepted raw values
.generatedAlwaysAs('some expression')

// ✅ After — only sql`` or () => sql``
.generatedAlwaysAs(sql`some expression`)
.generatedAlwaysAs(() => sql`some expression`)
```

#### `getTableColumns` deprecation

Use `getColumns` instead

```ts
// ❌ Before
import { getTableColumns } from 'drizzle-orm';

const columns = getTableColumns(users);

// ✅ After
import { getColumns } from 'drizzle-orm';

const columns = getColumns(users);
```

#### New migration folder structure (v3)

**Linked discussion**: [#2832](https://github.com/drizzle-team/drizzle-orm/discussions/2832)

<br/>

- No more `journal.json`
- SQL files and snapshots grouped into separate migration folders
- `drizzle-kit drop` command removed

These changes eliminate potential Git conflicts with the journal file and simplify the process of dropping or fixing conflicted migrations

<Callout type="info">
Read more on how to upgrade [here](/docs/mysql/upgrade-v1)
</Callout>


#### `drizzle-kit push --strict` deprecation

The `--strict` flag has been removed — its behavior is now the default. `drizzle-kit push` always prompts for confirmation for data-loss statements unless the `--force` flag is passed. Use [drizzle-kit push --explain](/docs/mysql/drizzle-kit-push) to preview the SQL that would be executed before running it.

#### Drizzle seed: UUID generator upgraded to v4

The UUID generator now produces RFC 4122 v4 compliant UUIDs, ensuring compatibility with Zod v4 validation. Use `{ version: '1' }` to keep old behavior, or `{ version: '2' | '3' }` for newer generators.

## Other features

#### New data types

New column types have been added to the MySQL dialect: `blob`, `tinyblob`, `mediumblob`, and `longblob`. You can read more [here](/docs/mysql/column-types#blob).

```ts
import { mysqlTable, blob, tinyblob, mediumblob, longblob } from 'drizzle-orm/mysql-core';

const files = mysqlTable('files', {
  tiny: tinyblob(),
  regular: blob(),
  medium: mediumblob(),
  large: longblob(),
});
```

#### JIT Mappers (opt-in)

Just-in-time compiled row mappers that make mapping as fast as the raw driver.
You can find out more [here](/docs/mysql/jit-mappers)

```ts {1}
const db = drizzle({ ..., jit: true });
```

#### New MSSQL dialect

New MSSQL dialect support added. You can read more [here](/docs/mssql/get-started-mssql)

#### New CockroachDB dialect

New CockroachDB dialect support added. You can read more [here](/docs/cockroach/get-started-cockroach)

#### New NetlifyDB driver

New NetlifyDB driver support added. You can read more [here](/docs/connect-netlify-db)

<Callout>
Note: The Netlify Database driver is developed and maintained by the Netlify team.
</Callout>

#### SQLcommenter support

Add custom tags to queries. Tags are appended as SQL comments at the end of each query. You can read more [here](/docs/sql-comments)

```ts
db.select().from(users).comment("my_first_tag");
// select "id", "name" from "users" /*my_first_tag*/
```

#### Column aliases via `.as()`

You can find out more aliasing info [here](/docs/aliases)
```ts
const query = db
  .select({ age: users.age.as('ageOfUser'), id: users.id.as('userId') })
  .from(users)
  .orderBy(asc(users.id.as('userId')));
```

#### Full `drizzle-kit` rewrite

The kit has been architecturally redesigned:
- Migrated from database snapshots to DDL snapshots
- Reworked diff detection and application
- Schema introspection reduced from ~10s to < 1s
- Added query hints and explain support for push

#### `drizzle-kit pull --init`

Creates the drizzle migration table and marks the first pulled migration as applied. You can read more [here](/docs/drizzle-kit-pull)

#### `drizzle-kit push --explain`

Shows the SQL that would be executed without actually running it. You can read more [here](/docs/drizzle-kit-push)

#### `drizzle-kit check` — commutativity check

Detects non-commutative migrations across branches — e.g., two branches altering the same column, or one renaming a table that another is altering.

How it works:
- Builds a DAG from snapshot `prevIds` to understand branch structure
- Finds fork points where branches diverged
- Computes the DDL diff from parent snapshot to each branch leaf
- Checks conflicts using a footprint map of which DDL statement types can interfere

If conflicts are found, the report tells you exactly which migrations on which branches are incompatible and which statements collide.

#### `drizzle-kit --ignore-conflicts` flag

Bypasses commutativity checks when you know the conflicts are expected.

#### `drizzle-kit generate`: migration conflict detection

`drizzle-kit generate` now identifies [incompatible changes](/docs/mysql/v0-v1-changes#drizzle-kit-check--commutativity-check) across migration branches. Use `--ignore-conflicts` to bypass.

#### Updates to the migration table

The migration table is automatically upgraded when you run `drizzle-kit up`. Two new columns are added:

- **`name`** — the full migration folder name (e.g. `20250220153045_brave_wolverine`)
- **`applied_at`** — timestamp of when the migration was executed (pre-existing rows are backfilled with `NULL`)

| Column | Type | v0 | v1 |
| --- | --- | --- |:---:|
| `id` | serial | yes | yes |
| `hash` | text | yes | yes |
| `created_at` | bigint | yes | yes (legacy) |
| `name` | text | — | new |
| `applied_at` | timestamp | — | new |

Migrations are now matched by their full folder name instead of timestamps. Even if two migrations are generated within the same second, the name suffix guarantees uniqueness.

During the upgrade, existing rows are backfilled using a multi-step strategy:
1. **Millis match** — truncate stored millis to seconds, match against local folder timestamps
2. **Hash tiebreaker** — if multiple migrations share the same second, disambiguate via the SQL hash
3. **Hash-only fallback** — if millis matching fails entirely, match by hash alone

<br/>
This means the upgrade handles all edge cases: normal single-developer projects, teams with closely-timed migrations, and even cases where the old journal data doesn't perfectly align with the new folder names.

#### Migrator applies all missing migrations

Previously the migrator only looked for local migrations with a creation date later than the last applied one. Now it detects and applies **every missing migration**, regardless of timestamp ordering. All migrations are matched against the full folder name (14-digit UTC timestamp + name suffix).

#### Top-level `await` in drizzle config files

Top-level `await` is now supported in `drizzle.config.ts` and schema files on Node.js.

#### Drizzle-kit: Build system improvements

- Migrated from `esbuild-register` to `tsx` loader — seamless ESM and CJS support
- Native Bun and Deno launch support

#### TS Schema file processing

Only files with the following extensions are processed: `.js`, `.mjs`, `.cjs`, `.jsx`, `.ts`, `.mts`, `.cts`, `.tsx`. All other file types are ignored.

#### Drizzle Seed: Ignore columns in refinements

Skip specific columns during seeding — the database default will be used instead:

```ts
await seed(db, schema).refine((f) => ({
  users: {
    count: 5,
    columns: {
      name: f.fullName(),
      photo: false, // skip — DB default will be used
    },
  },
}));
```

#### `min` / `max` parameters

Time-based generators now accept boundaries:

```ts
funcs.time({ min: '13:12:13', max: '15:12:13' })
funcs.timestamp({ min: '2024-01-01T00:00:00Z', max: '2025-01-01T00:00:00Z' })
funcs.datetime({ min: '2024-01-01', max: '2025-01-01' })
```

Source: https://orm.drizzle.team/docs/mysql/valibot

import Npm from '@mdx/Npm.astro';
import Callout from '@mdx/Callout.astro';

# valibot

### Install the dependencies

<Npm>
drizzle-orm@rc valibot
</Npm>

### Select schema

Defines the shape of data queried from the database - can be used to validate API responses.

```ts copy
import { int, mysqlTable, text } from 'drizzle-orm/mysql-core';
import { createSelectSchema } from 'drizzle-orm/valibot';
import { parse } from 'valibot';

const users = mysqlTable('users', {
  id: int().primaryKey().autoincrement(),
  name: text().notNull(),
  age: int().notNull()
});

const userSelectSchema = createSelectSchema(users);

const rows = await db.select({ id: users.id, name: users.name }).from(users).limit(1);
const parsed: { id: number; name: string; age: number } = parse(userSelectSchema, rows[0]); // Error: `age` is not returned in the above query

const rows = await db.select().from(users).limit(1);
const parsed: { id: number; name: string; age: number } = parse(userSelectSchema, rows[0]); // Will parse successfully
```

Views are also supported.

```ts copy
import { mysqlView } from 'drizzle-orm/mysql-core';
import { gt } from 'drizzle-orm';
import { createSelectSchema } from 'drizzle-orm/valibot';
import { parse } from 'valibot';

const usersView = mysqlView('users_view').as((qb) => qb.select().from(users).where(gt(users.age, 18)));
const usersViewSchema = createSelectSchema(usersView);
const parsed: { id: number; name: string; age: number } = parse(usersViewSchema, ...);
```

### Insert schema

Defines the shape of data to be inserted into the database - can be used to validate API requests.

```ts copy
import { int, mysqlTable, text } from 'drizzle-orm/mysql-core';
import { createInsertSchema } from 'drizzle-orm/valibot';
import { parse } from 'valibot';

const users = mysqlTable('users', {
  id: int().primaryKey().autoincrement(),
  name: text().notNull(),
  age: int().notNull()
});

const userInsertSchema = createInsertSchema(users);

const user = { name: 'John' };
const parsed: { id?: number | undefined, name: string, age: number } = parse(userInsertSchema, user); // Error: `age` is not defined

const user = { name: 'Jane', age: 30 };
const parsed: { id?: number | undefined, name: string, age: number } = parse(userInsertSchema, user); // Will parse successfully
await db.insert(users).values(parsed);
```

### Update schema

Defines the shape of data to be updated in the database - can be used to validate API requests.

```ts copy
import { int, mysqlTable, text } from 'drizzle-orm/mysql-core';
import { createUpdateSchema } from 'drizzle-orm/valibot';
import { parse } from 'valibot';
import { eq } from "drizzle-orm";

const users = mysqlTable('users', {
  id: int().primaryKey().autoincrement(),
  name: text().notNull(),
  age: int().notNull()
});

const userUpdateSchema = createUpdateSchema(users);

const user = { age: 35 };
const parsed: {
    id?: number | undefined;
    name?: string | undefined;
    age?: number | undefined;
} = parse(userUpdateSchema, user); // Will parse successfully

await db.update(users).set(parsed).where(eq(users.name, 'Jane'));
```

### Refinements

Each create schema function accepts an additional optional parameter that you can used to extend, modify or completely overwite a field's schema. Defining a callback function will extend or modify while providing a Valibot schema will overwrite it.

```ts copy
import { int, json, mysqlTable, text } from 'drizzle-orm/mysql-core';
import { createSelectSchema } from 'drizzle-orm/valibot';
import { parse, pipe, maxLength, object, string } from 'valibot';

const users = mysqlTable('users', {
  id: int().primaryKey().autoincrement(),
  name: text().notNull(),
  bio: text(),
  preferences: json()
});

const userSelectSchema = createSelectSchema(users, {
  name: (schema) => pipe(schema, maxLength(20)), // Extends schema
  bio: (schema) => pipe(schema, maxLength(1000)), // Extends schema before becoming nullable/optional
  preferences: object({ theme: string() }) // Overwrites the field, including its nullability
});

const parsed: {
  id: number;
  name: string,
  bio: string | null;
  preferences: {
    theme: string;
  };
} = parse(userSelectSchema, ...);
```

### Data type reference

```ts
mysql.boolean();

// Schema
boolean();
```

```ts
mysql.mysqlEnum('name', ['val1', 'val2']);

// Schema
enum({ val1: "val1", val2: "val2" });
```

```ts
mysql.date({ mode: 'date' });
mysql.datetime({ mode: 'date' });
mysql.timestamp({ mode: 'date' });

// Schema
date();
```

```ts
mysql.binary();
mysql.date({ mode: 'string' });
mysql.datetime({ mode: 'string' });
mysql.decimal();
mysql.time();
mysql.timestamp({ mode: 'string' });
mysql.varbinary();

// Schema
string();
```

```ts
mysql.tinyblob({ mode: 'string' });
mysql.tinyblob();

pipe(string(), maxLength(255))
```

```ts
mysql.blob({ mode: 'string' });
mysql.blob();

pipe(string(), maxLength(65_535))
```

```ts
mysql.mediumblob({ mode: 'string' });
mysql.mediumblob();

pipe(string(), maxLength(16_777_215))
```

```ts
mysql.longblob({ mode: 'string' });
mysql.longblob();

pipe(string(), maxLength(4_294_967_295))
```

```ts
mysql.char({ length: ... });

// Schema
pipe(string(), length(length));
```

```ts
mysql.varchar({ length: ... });

// Schema
pipe(string(), maxLength(length));
```

```ts
binary({ length: ... });

// Schema
pipe(string(), regex(/^[01]*$/), maxLength(length))
```

```ts
mysql.varbinary({ length: ... });

// Schema
pipe(string(), regex(/^[01]*$/), maxLength(length))
```

```ts
mysql.tinytext();

// Schema
pipe(string(), maxLength(255));
```

```ts
mysql.text();

// Schema
pipe(string(), maxLength(65_535));
```

```ts
mysql.mediumtext();

// Schema
pipe(string(), maxLength(16_777_215));
```

```ts
mysql.longtext();

// Schema
pipe(string(), maxLength(4_294_967_295));
```

```ts
mysql.tinytext({ enum: ... });
mysql.mediumtext({ enum: ... });
mysql.text({ enum: ... });
mysql.longtext({ enum: ... });
mysql.char({ enum: ... });
mysql.varchar({ enum: ... });

// Schema
enum(enum);
```

```ts
mysql.tinyint();

// Schema
pipe(number(), minValue(-128), maxValue(127), int()); // 8-bit integer lower and upper limit
```

```ts
mysql.tinyint({ unsigned: true });

// Schema
pipe(number(), minValue(0), maxValue(255), int()); // unsigned 8-bit integer lower and upper limit
```

```ts
mysql.smallint();

// Schema
pipe(number(), minValue(-32_768), maxValue(32_767), int()); // 16-bit integer lower and upper limit
```

```ts
mysql.smallint({ unsigned: true });

// Schema
pipe(number(), minValue(0), maxValue(65_535), int()); // unsigned 16-bit integer lower and upper limit
```

```ts
mysql.float();

// Schema
pipe(number(), minValue(-8_388_608), maxValue(8_388_607)); // 24-bit integer lower and upper limit
```

```ts
mysql.mediumint();

// Schema
pipe(number(), minValue(-8_388_608), maxValue(8_388_607), int()); // 24-bit integer lower and upper limit
```

```ts
mysql.float({ unsigned: true });

// Schema
pipe(number(), minValue(0), maxValue(16_777_215)); // unsigned 24-bit integer lower and upper limit
```

```ts
mysql.mediumint({ unsigned: true });

// Schema
pipe(number(), minValue(0), maxValue(16_777_215), int()); // unsigned 24-bit integer lower and upper limit
```

```ts
mysql.int();

// Schema
pipe(number(), minValue(-2_147_483_648), maxValue(2_147_483_647), int()); // 32-bit integer lower and upper limit
```

```ts
mysql.int({ unsigned: true });

// Schema
pipe(number(), minValue(0), maxValue(4_294_967_295), int()); // unsgined 32-bit integer lower and upper limit
```

```ts
mysql.double();
mysql.real();

// Schema
pipe(number(), minValue(-140_737_488_355_328), maxValue(140_737_488_355_327)); // 48-bit integer lower and upper limit
```

```ts
mysql.double({ unsigned: true });

// Schema
pipe(number(), minValue(0), maxValue(281_474_976_710_655)); // unsigned 48-bit integer lower and upper limit
```

```ts
mysql.decimal({ mode: 'number' });

// Schema
pipe(number(), minValue(-9_007_199_254_740_991), maxValue(9_007_199_254_740_991))
```

```ts
mysql.decimal({ mode: 'bigint' });

// Schema
pipe(bigint(), minValue(-9_223_372_036_854_775_808n), maxValue(9_223_372_036_854_775_807n))
```

```ts
mysql.decimal({ mode: 'number', unsigned: true });

// Schema
pipe(number(), minValue(0), maxValue(9_007_199_254_740_991))
```

```ts
mysql.decimal({ mode: 'bigint', unsigned: true });

// Schema
pipe(bigint(), minValue(0), maxValue(18_446_744_073_709_551_615n))
```

```ts
mysql.bigint({ mode: 'number' });

// Schema
pipe(number(), minValue(-9_007_199_254_740_991), maxValue(9_007_199_254_740_991), int()); // Javascript min. and max. safe integers
```

```ts
mysql.bigint({ mode: 'number', unsigned: true });

// Schema
pipe(number(), minValue(0), maxValue(9_007_199_254_740_991), int()); // Javascript min. and max. safe integers
```

```ts
mysql.bigint({ mode: 'string' });

// Schema
pipe(
	string(),
	regex(/^-?\d+$/),
	transform((v) => BigInt(v)),
	minValue(-9_223_372_036_854_775_808n),
	maxValue(9_223_372_036_854_775_807n),
	transform((v) => v.toString()),
)
```

```ts
mysql.bigint({ mode: 'string', unsigned: true });

// Schema
pipe(
	string(),
	regex(/^\d+$/),
	transform((v) => BigInt(v)),
	minValue(0n),
	maxValue(9_223_372_036_854_775_807n),
	transform((v) => v.toString()),
);
```

```ts
mysql.bigint({ mode: 'bigint' });

// Schema
pipe(bigint(), minValue(-9_223_372_036_854_775_808n), maxValue(9_223_372_036_854_775_807n)); // 64-bit integer lower and upper limit
```

```ts
mysql.bigint({ mode: 'bigint', unsigned: true });

// Schema
pipe(bigint(), minValue(0n), maxValue(18_446_744_073_709_551_615n)); // unsigned 64-bit integer lower and upper limit
```

```ts
mysql.serial();

// Schema
pipe(number(), minValue(0), maxValue(9_007_199_254_740_991), int()); // Javascript max. safe integer
```

```ts
mysql.year();

// Schema
pipe(number(), minValue(1_901), maxValue(2_155), int());
```

```ts
mysql.json();

// Schema
union([union([string(), number(), boolean(), null_()]), array(any()), record(string(), any())]);
```


Source: https://orm.drizzle.team/docs/mysql/views

import Callout from '@mdx/Callout.astro';
import Section from '@mdx/Section.astro';

# Views

There're several ways you can declare views with Drizzle ORM.  

You can declare views that have to be created or you can declare views that already exist in the database. 

You can declare views statements with an inline `query builder` syntax, with `standalone query builder` and with raw `sql` operators. 

When views are created with either inlined or standalone query builders, view columns schema will be automatically inferred, 
yet when you use `sql` you have to explicitly declare view columns schema.

### Declaring views

<Section>
      ```ts filename="schema.ts" copy {14-15}
      import { text, mysqlTable, mysqlView, int, timestamp } from "drizzle-orm/mysql-core";
      import { eq } from "drizzle-orm";

      export const user = mysqlTable("user", {
        id: int().primaryKey().autoincrement(),
        name: text(),
        email: text(),
        password: text(),
        role: text().$type<"admin" | "customer">(),
        createdAt: timestamp("created_at"),
        updatedAt: timestamp("updated_at"),
      });

      export const userView = mysqlView("user_view").as((qb) => qb.select().from(user));
      export const customersView = mysqlView("customers_view").as((qb) => qb.select().from(user).where(eq(user.role, "customer")));
      ```
      ```sql
      ...

      CREATE ALGORITHM = undefined SQL SECURITY definer VIEW `customers_view` AS (select * from `user` where `user`.`role` = 'customer');
      CREATE ALGORITHM = undefined SQL SECURITY definer VIEW `user_view` AS (select * from `user`);
      ```
    </Section>

You can also declare views using `standalone query builder`, it works exactly the same way:

<Section>
      ```ts filename="schema.ts" copy {4,16-17}
      import { text, mysqlTable, mysqlView, int, timestamp, QueryBuilder } from "drizzle-orm/mysql-core";
      import { eq } from "drizzle-orm";

      const qb = new QueryBuilder();

      export const user = mysqlTable("user", {
        id: int().primaryKey().autoincrement(),
        name: text(),
        email: text(),
        password: text(),
        role: text().$type<"admin" | "customer">(),
        createdAt: timestamp("created_at"),
        updatedAt: timestamp("updated_at"),
      });

      export const userView = mysqlView("user_view").as(qb.select().from(user));
      export const customersView = mysqlView("customers_view").as(qb.select().from(user).where(eq(user.role, "customer")));
      ```
      ```sql
	  ...

      CREATE ALGORITHM = undefined SQL SECURITY definer VIEW `customers_view` AS (select * from `user` where `user`.`role` = 'customer');
      CREATE ALGORITHM = undefined SQL SECURITY definer VIEW `user_view` AS (select * from `user`);
      ```
    </Section>

### Declaring views with raw SQL
Whenever you need to declare view using a syntax that is not supported by the query builder, 
you can directly use `sql` operator and explicitly specify view columns schema.

```ts copy {15}
// regular view
import { eq, sql } from "drizzle-orm";
import { int, mysqlTable, mysqlView, text, timestamp } from "drizzle-orm/mysql-core";

export const users = mysqlTable("users", {
  id: int().primaryKey().autoincrement(),
  name: text(),
  cityId: int("city_id"),
});

export const newYorkers = mysqlView("new_yorkers", {
  id: int().primaryKey().autoincrement(),
  name: text().notNull(),
  cityId: int("city_id").notNull(),
}).as(sql`select * from ${users} where ${eq(users.cityId, 1)}`);
```
```sql
...

CREATE ALGORITHM = undefined SQL SECURITY definer VIEW `new_yorkers` AS (select * from `users` where `users`.`city_id` = 1);
```

### Declaring existing views
When you're provided with a read only access to an existing view in the database you should use `.existing()` view configuration, 
`drizzle-kit` will ignore and will not generate a `create view` statement in the generated migration.
```ts {18}
import { int, mysqlTable, mysqlView, text, timestamp } from "drizzle-orm/mysql-core";

export const user = mysqlTable("user", {
  id: int().primaryKey().autoincrement(),
  name: text(),
  email: text(),
  password: text(),
  role: text().$type<"admin" | "customer">(),
  createdAt: timestamp("created_at"),
  updatedAt: timestamp("updated_at"),
});

// regular view
export const trimmedUser = mysqlView("trimmed_user", {
  id: int("id"),
  name: text("name"),
  email: text("email"),
}).existing();
```


Source: https://orm.drizzle.team/docs/mysql/zod

import Npm from '@mdx/Npm.astro';
import Callout from '@mdx/Callout.astro';

# zod

### Install the dependencies

<Npm>
drizzle-orm@rc zod
</Npm>

### Select schema

Defines the shape of data queried from the database - can be used to validate API responses.

```ts copy
import { int, mysqlTable, text } from 'drizzle-orm/mysql-core';
import { createSelectSchema } from 'drizzle-orm/zod';

const users = mysqlTable('users', {
  id: int().primaryKey().autoincrement(),
  name: text().notNull(),
  age: int().notNull()
});

const userSelectSchema = createSelectSchema(users);

const rows = await db.select({ id: users.id, name: users.name }).from(users).limit(1);
const parsed: { id: number; name: string; age: number } = userSelectSchema.parse(rows[0]); // Error: `age` is not returned in the above query

const rows = await db.select().from(users).limit(1);
const parsed: { id: number; name: string; age: number } = userSelectSchema.parse(rows[0]); // Will parse successfully
```

Views are also supported.

```ts copy
import { mysqlView } from 'drizzle-orm/mysql-core';
import { gt } from 'drizzle-orm';
import { createSelectSchema } from 'drizzle-orm/zod';

const usersView = mysqlView('users_view').as((qb) => qb.select().from(users).where(gt(users.age, 18)));
const usersViewSchema = createSelectSchema(usersView);
const parsed: { id: number; name: string; age: number } = usersViewSchema.parse(...);
```

### Insert schema

Defines the shape of data to be inserted into the database - can be used to validate API requests.

```ts copy
import { int, mysqlTable, text } from 'drizzle-orm/mysql-core';
import { createInsertSchema } from 'drizzle-orm/zod';

const users = mysqlTable('users', {
  id: int().primaryKey().autoincrement(),
  name: text().notNull(),
  age: int().notNull()
});

const userInsertSchema = createInsertSchema(users);

const user = { name: 'John' };
const parsed: { id?: number | undefined, name: string, age: number } = userInsertSchema.parse(user); // Error: `age` is not defined

const user = { name: 'Jane', age: 30 };
const parsed: { id?: number | undefined, name: string, age: number } = userInsertSchema.parse(user); // Will parse successfully
await db.insert(users).values(parsed);
```

### Update schema

Defines the shape of data to be updated in the database - can be used to validate API requests.

```ts copy
import { int, mysqlTable, text } from 'drizzle-orm/mysql-core';
import { createUpdateSchema } from 'drizzle-orm/zod';
import { eq } from "drizzle-orm";

const users = mysqlTable('users', {
  id: int().primaryKey().autoincrement(),
  name: text().notNull(),
  age: int().notNull()
});

const userUpdateSchema = createUpdateSchema(users);

const user = { age: 35 };
const parsed: 
	{ 
		id?: number | undefined; 
		name?: string | undefined; 
		age?: number | undefined 
	} = userUpdateSchema.parse(user); // Will parse successfully

await db.update(users).set(parsed).where(eq(users.name, 'Jane'));
```

### Refinements

Each create schema function accepts an additional optional parameter that you can used to extend, modify or completely overwite a field's schema. Defining a callback function will extend or modify while providing a Zod schema will overwrite it.

```ts copy
import { int, json, mysqlTable, text } from 'drizzle-orm/mysql-core';
import { createSelectSchema } from 'drizzle-orm/zod';
import { z } from 'zod/v4';

const users = mysqlTable('users', {
  id: int().primaryKey(),
  name: text().notNull(),
  bio: text(),
  preferences: json()
});

const userSelectSchema = createSelectSchema(users, {
  name: (schema) => schema.max(20), // Extends schema
  bio: (schema) => schema.max(1000), // Extends schema before becoming nullable/optional
  preferences: z.object({ theme: z.string() }) // Overwrites the field, including its nullability
});

const parsed: {
  id: number;
  name: string,
  bio: string | null;
  preferences: {
    theme: string;
  };
} = userSelectSchema.parse(...);
```

### Factory functions

For more advanced use cases, you can use the `createSchemaFactory` function.

**Use case: Using an extended Zod instance**

```ts copy
import { int, mysqlTable, text } from 'drizzle-orm/mysql-core';
import { createSchemaFactory } from 'drizzle-orm/zod';
import { z } from '@hono/zod-openapi'; // Extended Zod instance

const users = mysqlTable('users', {
  id: int().primaryKey().autoincrement(),
  name: text().notNull(),
  age: int().notNull()
});

const { createInsertSchema } = createSchemaFactory({ zodInstance: z });

const userInsertSchema = createInsertSchema(users, {
  // We can now use the extended instance
  name: (schema) => schema.openapi({ example: 'John' })
});
```

**Use case: Type coercion**

```ts copy
import { mysqlTable, timestamp } from 'drizzle-orm/mysql-core';
import { createSchemaFactory } from 'drizzle-orm/zod';
import { z } from 'zod/v4';

const users = mysqlTable('users', {
  ...,
  createdAt: timestamp().notNull()
});

const { createInsertSchema } = createSchemaFactory({
  // This configuration will only coerce dates. Set `coerce` to `true` to coerce all data types or specify others
  coerce: {
    date: true
  }
});

const userInsertSchema = createInsertSchema(users);
// The above is the same as this:
const userInsertSchema = z.object({
  ...,
  createdAt: z.coerce.date()
});
```

### Data type reference

```ts
mysql.boolean();

// Schema
z.boolean();
```

```ts
mysql.mysqlEnum('name', ['val1', 'val2']);

// Schema
z.enum(['val1', 'val2']);
```

```ts
mysql.date({ mode: 'date' });
mysql.datetime({ mode: 'date' });
mysql.timestamp({ mode: 'date' });

// Schema
z.date();
```

```ts
mysql.binary();
mysql.date({ mode: 'string' });
mysql.datetime({ mode: 'string' });
mysql.decimal();
mysql.time();
mysql.timestamp({ mode: 'string' });
mysql.varbinary();

// Schema
z.string();
```

```ts
mysql.tinyblob({ mode: 'string' });
mysql.tinyblob();

z.string().max(255)
```

```ts
mysql.blob({ mode: 'string' });
mysql.blob();

z.string().max(65_535)
```

```ts
mysql.mediumblob({ mode: 'string' });
mysql.mediumblob();

z.string().max(16_777_215)
```

```ts
mysql.longblob({ mode: 'string' });
mysql.longblob();

z.string().max(4_294_967_295)
```

```ts
mysql.char({ length: ... });

// Schema
z.string().length(length);
```

```ts
mysql.varchar({ length: ... });

// Schema
z.string().max(length);
```

```ts
mysql.binary({ length: ... });

// Schema
schema.regex(/^[01]*$/).max(length);
```

```ts
mysql.varbinary({ length: ... });

// Schema
schema.regex(/^[01]*$/).max(length);
```

```ts
mysql.tinytext();

// Schema
z.string().max(255);
```

```ts
mysql.text();

// Schema
z.string().max(65_535);
```

```ts
mysql.mediumtext();

// Schema
z.string().max(16_777_215);
```

```ts
mysql.longtext();

// Schema
z.string().max(4_294_967_295);
```

```ts
mysql.tinytext({ enum: ... });
mysql.mediumtext({ enum: ... });
mysql.text({ enum: ... });
mysql.longtext({ enum: ... });
mysql.char({ enum: ... });
mysql.varchar({ enum: ... });

// Schema
z.enum(enum);
```

```ts
mysql.tinyint();

// Schema
z.number().min(-128).max(127).int(); // 8-bit integer lower and upper limit
```

```ts
mysql.tinyint({ unsigned: true });

// Schema
z.number().min(0).max(255).int(); // unsigned 8-bit integer lower and upper limit
```

```ts
mysql.smallint();

// Schema
z.number().min(-32_768).max(32_767).int(); // 16-bit integer lower and upper limit
```

```ts
mysql.smallint({ unsigned: true });

// Schema
z.number().min(0).max(65_535).int(); // unsigned 16-bit integer lower and upper limit
```

```ts
mysql.float();

// Schema
z.number().min(-8_388_608).max(8_388_607); // 24-bit integer lower and upper limit
```

```ts
mysql.mediumint();

// Schema
z.number().min(-8_388_608).max(8_388_607).int(); // 24-bit integer lower and upper limit
```

```ts
mysql.float({ unsigned: true });

// Schema
z.number().min(0).max(16_777_215); // unsigned 24-bit integer lower and upper limit
```

```ts
mysql.mediumint({ unsigned: true });

// Schema
z.number().min(0).max(16_777_215).int(); // unsigned 24-bit integer lower and upper limit
```

```ts
mysql.int();

// Schema
z.number().min(-2_147_483_648).max(2_147_483_647).int(); // 32-bit integer lower and upper limit
```

```ts
mysql.int({ unsigned: true });

// Schema
z.number().min(0).max(4_294_967_295).int(); // unsgined 32-bit integer lower and upper limit
```

```ts
mysql.double();
mysql.real();

// Schema
z.number().min(-140_737_488_355_328).max(140_737_488_355_327); // 48-bit integer lower and upper limit
```

```ts
mysql.double({ unsigned: true });

// Schema
z.number().min(0).max(281_474_976_710_655); // unsigned 48-bit integer lower and upper limit
```

```ts
mysql.decimal({ mode: 'number' });

// Schema
z.number().min(-9_007_199_254_740_991).max(9_007_199_254_740_991);
```

```ts
mysql.decimal({ mode: 'bigint' });

// Schema
z.bigint().min(-9_223_372_036_854_775_808n).max(9_223_372_036_854_775_807n);
```

```ts
mysql.decimal({ mode: 'number', unsigned: true });

// Schema
z.number().min(0).max(9_007_199_254_740_991);
```

```ts
mysql.decimal({ mode: 'bigint', unsigned: true });

// Schema
z.bigint().min(0).max(18_446_744_073_709_551_615n);
```

```ts
mysql.bigint({ mode: 'number' });

// Schema
z.number().min(-9_007_199_254_740_991).max(9_007_199_254_740_991).int(); // Javascript min. and max. safe integers
```

```ts
mysql.bigint({ mode: 'number', unsigned: true });

// Schema
z.number().min(0).max(9_007_199_254_740_991).int(); // Javascript max safe integer
```

```ts
mysql.bigint({ mode: 'string' });

// Schema
z.string().regex(/^-?\d+$/).transform(BigInt).pipe(
	zod.bigint().gte(-9_223_372_036_854_775_808n).lte(9_223_372_036_854_775_807n),
).transform(String)
```

```ts
mysql.bigint({ mode: 'string', unsigned: true });

// Schema
z.string().regex(/^\d+$/).transform(BigInt).pipe(
	zod.bigint().gte(0n).lte(9_223_372_036_854_775_807n),
).transform(String)
```

```ts
mysql.bigint({ mode: 'bigint' });

// Schema
z.bigint().min(-9_223_372_036_854_775_808n).max(9_223_372_036_854_775_807n); // 64-bit integer lower and upper limit
```

```ts
mysql.bigint({ mode: 'bigint', unsigned: true });

// Schema
z.bigint().min(0).max(18_446_744_073_709_551_615n); // unsigned 64-bit integer lower and upper limit
```

```ts
mysql.serial();

// Schema
z.number().min(0).max(9_007_199_254_740_991).int(); // Javascript max. safe integer
```


```ts
mysql.year();

// Schema
z.number().min(1_901).max(2_155).int();
```

```ts
mysql.json();

// Schema
z.union([z.union([z.string(), z.number(), z.boolean(), z.null()]), z.record(z.any()), z.array(z.any())]);
```


Source: https://orm.drizzle.team/docs/overview

import Callout from '@mdx/Callout.astro';
import CodeTabs from '@mdx/CodeTabs.astro';
import YoutubeCards from '@mdx/YoutubeCards.astro';
import GetStartedLinks from '@mdx/GetStartedLinks/index.astro'

# Drizzle ORM

Drizzle ORM is a headless TypeScript ORM with a head. 🐲
> Drizzle is a good friend who's there for you when necessary and doesn't bother when you need some space.

It looks and feels simple, performs on day _1000_ of your project,\
lets you do things your way, and is there when you need it.

**It's the only ORM with both [relational](/docs/rqb) and [SQL-like](/docs/select) query APIs**, 
providing you the best of both worlds when it comes to accessing your relational data. 
Drizzle is lightweight, performant, typesafe, non-lactose, gluten-free, sober, flexible and **serverless-ready by design**.
Drizzle is not just a library, it's an experience. 🤩

[![Drizzle bestofjs](@/assets/images/bestofjs.jpg)](https://bestofjs.org/projects/drizzle-orm)

## Headless ORM? 
First and foremost, Drizzle is a library and a collection of complementary opt-in tools. 

**ORM** stands for _object relational mapping_, and developers tend to call Django-like or Spring-like tools an ORM. 
We truly believe it's a misconception based on legacy nomenclature, and we call them **data frameworks**.

<Callout type="error" emoji="️💔">
  With data frameworks you have to build projects **around them** and not **with them**.
</Callout>

**Drizzle** lets you build your project the way you want, without interfering with your project or structure. 

Using Drizzle you can define and manage database schemas in TypeScript, access your data in a SQL-like 
or relational way, and take advantage of opt-in tools 
to push your developer experience _through the roof_. 🤯 

## Why SQL-like?
**If you know SQL, you know Drizzle.**

Other ORMs and data frameworks tend to deviate/abstract you away from SQL, which 
leads to a double learning curve: needing to know both SQL and the framework's API.  

Drizzle is the opposite. 
We embrace SQL and built Drizzle to be SQL-like at its core, so you can have zero to no 
learning curve and access to the full power of SQL.  

We bring all the familiar **[SQL schema](/docs/sql-schema-declaration)**, **[queries](/docs/select)**, 
**[automatic migrations](/docs/migrations)** and **[one more thing](/docs/rqb)**. ✨

<CodeTabs items={["index.ts", "schema.ts", "migration.sql"]}>
```typescript copy
// Access your data
await db
	.select()
	.from(countries)
	.leftJoin(cities, eq(cities.countryId, countries.id))
	.where(eq(countries.id, 10))
```
```typescript copy
// manage your schema
export const countries = pgTable('countries', {
  id: serial('id').primaryKey(),
  name: varchar('name', { length: 256 }),
});

export const cities = pgTable('cities', {
  id: serial('id').primaryKey(),
  name: varchar('name', { length: 256 }),
  countryId: integer('country_id').references(() => countries.id),
});
```
```sql
-- generate migrations
CREATE TABLE IF NOT EXISTS "countries" (
	"id" serial PRIMARY KEY NOT NULL,
	"name" varchar(256)
);

CREATE TABLE IF NOT EXISTS "cities" (
	"id" serial PRIMARY KEY NOT NULL,
	"name" varchar(256),
	"country_id" integer
);

ALTER TABLE "cities" ADD CONSTRAINT "cities_country_id_countries_id_fk" FOREIGN KEY ("country_id") REFERENCES "countries"("id") ON DELETE no action ON UPDATE no action;
```
</CodeTabs>

## Why not SQL-like?
We're always striving for a perfectly balanced solution, and while SQL-like does cover 100% of the needs, 
there are certain common scenarios where you can query data in a better way.  

We've built the **[Queries API](/docs/rqb)** for you, so you can fetch relational nested data from the database 
in the most convenient and performant way, and never think about joins and data mapping.  

**Drizzle always outputs exactly 1 SQL query.** Feel free to use it with serverless databases and never worry about performance or roundtrip costs!

```ts
const result = await db.query.users.findMany({
	with: {
		posts: true
	},
});
```

## Serverless?
<Callout type="info" emoji="🥳">
  The best part is no part. **Drizzle has exactly 0 dependencies!**
</Callout>


![Drizzle is slim an Serverless ready](@/assets/images/drizzle31kb.jpg)
  
Drizzle ORM is dialect-specific, slim, performant and serverless-ready **by design**.  

We've spent a lot of time to make sure you have best-in-class SQL dialect support, including Postgres, MySQL, and others.

Drizzle operates natively through industry-standard database drivers. We support all major **[PostgreSQL](/docs/get-started-postgresql)**, **[MySQL](/docs/mysql/get-started-mysql)**, **[SQLite](/docs/sqlite/get-started-sqlite)** or **[SingleStore](/docs/singlestore/get-started-singlestore)** drivers out there, and we're adding new ones **[really fast](https://twitter.com/DrizzleORM/status/1653082492742647811?s=20)**.  


## Welcome on board!
More and more companies are adopting Drizzle in production, experiencing immense benefits in both DX and performance.

**We're always there to help, so don't hesitate to reach out. We'll gladly assist you in your Drizzle journey!**

We have an outstanding **[Discord community](https://driz.link/discord)** and welcome all builders to our **[Twitter](https://twitter.com/drizzleorm)**.
  
Now go build something awesome with Drizzle and your **[PostgreSQL](/docs/get-started-postgresql)**, **[MySQL](/docs/mysql/get-started-mysql)** or **[SQLite](/docs/sqlite/get-started-sqlite)** database. 🚀

### Video Showcase

{/* tRPC + NextJS App Router = Simple Typesafe APIs
Jack Herrington 19:17
https://www.youtube.com/watch?v=qCLV0Iaq9zU */}
{/* https://www.youtube.com/watch?v=qDunJ0wVIec */}
{/* https://www.youtube.com/watch?v=NZpPMlSAez0 */}

 {/* https://www.youtube.com/watch?v=-A0kMiJqQRY */}

<YoutubeCards cards={[
	{
		id: "vyU5mJGCJMw",
		title: "Full Drizzle Course for Beginners",
		description: "Code Genix",
		time: "1:37:39",
	},
	{
		id: "7-NZ0MlPpJA",
		title: "Learn Drizzle In 60 Minutes",
		description: "Web Dev Simplified",
		time: "56:09"
	},
	{
		id: "i_mAHOhpBSA",
		title: "Drizzle ORM in 100 Seconds",
		description: "Fireship",
		time: "2:55"
	},
	{
		id: "hIYNOiZXQ7Y",
		title: "Learn Drizzle ORM in 13 mins (crash course)",
		description: "Neon",
		time: "14:00"
	},
	{
		id: "4ZhtoOFKFP8",
		title: "Easiest Database Setup in Next.js&nbsp;14 with Turso&nbsp;&&nbsp;Drizzle",
		description: "Sam Meech-Ward",
		time: '38:08'
	}, 
	{
		id: "NfVELsEZFsA",
		title: "Next.js Project with Vercel, Neon, Drizzle, TailwindCSS, FlowBite and more!",
		description: "CodingEntrepreneurs",
		time: '5:46:28'
	}, 
	{
		id: "_SLxGYzv6jo",
		title: "I Have A New Favorite Database&nbsp;Tool",
		description: "Theo - t3.gg",
		time: '5:46'
	}, 
	{
		id: "Qo-RXkSwOtc",
		title: "Drizzle ORM First impressions - migrations, relations, queries!",
		description: "Marius Espejo",
		time: '33:52'
	},
	{
		id: "yXNEqyvA0OY",
		title: "I want to learn Drizzle ORM, so I'm starting another next14 project",
		description: "Web Dev Cody",
		time: "9:00"
	},
	{
		id: "h7vVhR-dFYo",
		title: "Picking an ORM is Getting Harder...",
		description: "Ben Davis",
		time: "5:18"
	},
	{
		id: "8met6WTk0mQ",
		title: "This New Database Tool is a Game-Changer",
		description: "Josh tried coding",
		time: "8:49"
	},
	{
		id: "woWW1T9DXEY",
		title: "My Favorite Database Tool Just Got EVEN Better",
		description: "Josh tried coding",
		time: "4:23"
	},
	{
		id: "A3l6YYkXzzg",
		title: "SaaS Notion Clone with Realtime cursors, Nextjs 13, Stripe, Drizzle ORM, Tailwind, Supabase, Sockets",
		description: "Web Prodigies",
		time: "11:41:46"
	},
	{
		id: "EQfaw5bDE1s",
		title: "SvelteKit + Drizzle Code Breakdown",
		description: "Ben Davis",
		time: "12:18"
	},
	{
		id: "b6VhN_HHDiQ",
		title: "Build a Multi-Tenanted, Role-Based Access Control System",
		description: "TomDoesTech",
		time: "2:01:29"
	},
	/*
	This video became private
	Uncomment (in other files too) it when it becomes public again
	{
		id: "3tl9XCiQErA",
		title: "The Prisma killer is finally here",
		description: "SST",
		time: "5:42"
	},
	*/
	{
		id: "VQFjyEa8vGE",
		title: "Learning Drizzle ORM and working on a next14 project",
		description: "Web Dev Cody",
		time: "1:07:41"
	},
	{
		id: "5G0upg4sxgE",
		title: "This Trick Makes My Favorite Database Tool Even Better",
		description: "Josh tried coding",
		time: "6:01"
	},
	{
		id: "-JnEuvPmt-Q",
		title: "Effortless Auth in Next.js 14: Use Auth.js & Drizzle ORM for Secure Login",
		description: "Sam Meech-Ward",
		time: "26:29"
	},
]} />


Source: https://orm.drizzle.team/docs/perf-serverless

# Drizzle Serverless performance

You can get immense benefits with `serverless functions` like AWS Lambda or Vercel Server Functions (they're AWS Lambda based), 
since they can live up to 15mins and reuse both database connections and prepared statements.

On the other, hand `edge functions` tend to clean up straight after they're invoked which leads to little to no performance benefits.
  
To reuse your database connection and prepared statements you just have to declare them outside of handler scope:
```ts
const databaseConnection = ...;
const db = drizzle({ client: databaseConnection });
const prepared = db.select().from(...).prepare();

// AWS handler
export const handler = async (event: APIGatewayProxyEvent) => {
  return prepared.execute();
}
```


Source: https://orm.drizzle.team/docs/pg/aliases

import Section from '@mdx/Section.astro';

# Aliases
Drizzle supports aliasing for tables, columns, subqueries and CTEs — mapping directly to the SQL `AS` keyword.

### Table aliasing
You can alias tables using the `alias` function. This is useful when you need to join the same table multiple times, 
for example in self-referencing relationships like employees and their managers:

<Section>
```ts copy {9}
import { alias, pgTable, integer, text } from "drizzle-orm/pg-core";

const employees = pgTable("employees", {
  id: integer().primaryKey(),
  name: text(),
  managerId: integer("manager_id"),
});

const manager = alias(employees, "manager");

await db.select({
  employeeName: employees.name,
  managerName: manager.name,
})
  .from(employees)
  .leftJoin(manager, eq(employees.managerId, manager.id));
```
```sql
select "employees"."name", "manager"."name"
from "employees"
left join "employees" as "manager" on "employees"."manager_id" = "manager"."id";
```
</Section>

### Column aliasing
You can alias columns using the `.as()` method on columns and `sql` expressions.
This maps directly to the SQL `AS` keyword and lets you control the name of a column in the query result:

<Section>
```ts {3}
const result = await db.select({
  id: users.id,
  lowerName: users.name.as("lower_name"),
}).from(users);
```
```sql
select "id", "name" as "lower_name" from "users";
```
</Section>

You can also use `.as()` with `sql` expressions:

<Section>
```ts {3}
const result = await db.select({
  id: users.id,
  lowerName: sql<string>`lower(${users.name})`.as("lower_name"),
}).from(users);
```
```sql
select "id", lower("name") as "lower_name" from "users";
```
</Section>

### Subquery aliasing
When using a subquery as a data source, you must provide an alias using `.as()`. 
This lets you reference the subquery's columns in the outer query:

<Section>
```ts
const sq = db.select().from(users).where(eq(users.id, 42)).as('sq');

const result = await db.select().from(sq);
```
```sql
select "id", "name", "age" from (select "id", "name", "age" from "users" where "users"."id" = 42) "sq";
```
</Section>

Subqueries can also be used in joins:

<Section>
```ts
const sq = db.select().from(users).where(eq(users.id, 42)).as('sq');

const result = await db.select().from(users).leftJoin(sq, eq(users.id, sq.id));
```
```sql
select "users"."id", "users"."name", "users"."age", "sq"."id", "sq"."name", "sq"."age"
  from "users"
  left join (select "id", "name", "age" from "users" where "users"."id" = 42) "sq"
    on "users"."id" = "sq"."id";
```
</Section>

### CTE aliasing
Common table expressions (CTEs) are aliased using `db.$with('alias')`. 
The alias name is used to reference the CTE in the main query:

<Section>
```ts
const sq = db.$with('sq').as(db.select().from(users).where(eq(users.id, 42)));

const result = await db.with(sq).select().from(sq);
```
```sql
with "sq" as (select "id", "name", "age" from "users" where "users"."id" = 42)
select "id", "name", "age" from "sq";
```
</Section>

When using `sql` expressions inside a CTE, you need to alias them with `.as()` to be able to reference them in the outer query:

<Section>
```ts
const sq = db.$with('sq').as(db.select({
  name: sql<string>`upper(${users.name})`.as('name'),
}).from(users));

const result = await db.with(sq).select({ name: sq.name }).from(sq);
```
```sql
with "sq" as (select upper("name") as "name" from "users")
select "name" from "sq";
```
</Section>

Source: https://orm.drizzle.team/docs/pg/arktype

import Npm from '@mdx/Npm.astro';
import Callout from '@mdx/Callout.astro';

# arktype

### Install the dependencies

<Npm>
drizzle-orm@rc arktype
</Npm>

### Select schema

Defines the shape of data queried from the database - can be used to validate API responses.

```ts copy
import { pgTable, text, integer } from 'drizzle-orm/pg-core';
import { createSelectSchema } from 'drizzle-orm/arktype';
import { ArkErrors } from "arktype";

const users = pgTable('users', {
  id: integer().generatedAlwaysAsIdentity().primaryKey(),
  name: text().notNull(),
  age: integer().notNull()
});

const userSelectSchema = createSelectSchema(users);

const rows = await db.select({ id: users.id, name: users.name }).from(users).limit(1);
const parsed: ArkErrors | { id: number; name: string; age: number } = userSelectSchema(rows[0]); // Error: `age` is not returned in the above query

const rows = await db.select().from(users).limit(1);
const parsed: ArkErrors | { id: number; name: string; age: number } = userSelectSchema(rows[0]); // Will parse successfully
```

Views and enums are also supported.

```ts copy
import { pgEnum, pgView } from 'drizzle-orm/pg-core';
import { gt } from 'drizzle-orm';
import { createSelectSchema } from 'drizzle-orm/arktype';
import { ArkErrors } from "arktype";

const roles = pgEnum('roles', ['admin', 'basic']);
const rolesSchema = createSelectSchema(roles);
const parsed: ArkErrors | 'admin' | 'basic' = rolesSchema(...);

const usersView = pgView('users_view').as((qb) => qb.select().from(users).where(gt(users.age, 18)));
const usersViewSchema = createSelectSchema(usersView);
const parsed: ArkErrors | { id: number; name: string; age: number } = usersViewSchema(...);
```

### Insert schema

Defines the shape of data to be inserted into the database - can be used to validate API requests.

```ts copy
import { pgTable, text, integer } from 'drizzle-orm/pg-core';
import { createInsertSchema } from 'drizzle-orm/arktype';
import { ArkErrors } from "arktype";

const users = pgTable('users', {
  id: integer().generatedAlwaysAsIdentity().primaryKey(),
  name: text().notNull(),
  age: integer().notNull()
});

const userInsertSchema = createInsertSchema(users);

const user = { name: 'John' };
const parsed: ArkErrors | { name: string, age: number } = userInsertSchema(user); // Error: `age` is not defined

const user = { name: 'Jane', age: 30 };
const parsed: ArkErrors | { name: string, age: number } = userInsertSchema(user); // Will parse successfully

if (parsed instanceof ArkErrors) {
  console.error(parsed.summary);
  process.exit(1);
}

await db.insert(users).values(parsed);
```

### Update schema

Defines the shape of data to be updated in the database - can be used to validate API requests.

```ts copy
import { pgTable, text, integer } from 'drizzle-orm/pg-core';
import { createUpdateSchema } from 'drizzle-orm/arktype';
import { eq } from "drizzle-orm";
import { ArkErrors } from "arktype";

const users = pgTable('users', {
  id: integer().generatedAlwaysAsIdentity().primaryKey(),
  name: text().notNull(),
  age: integer().notNull()
});

const userUpdateSchema = createUpdateSchema(users);

const user = { age: 35 };
const parsed: ArkErrors | { name?: string | undefined, age?: number | undefined } = userUpdateSchema(user); // Will parse successfully

if (parsed instanceof ArkErrors) {
  console.error(parsed.summary);
  process.exit(1);
}

await db.update(users).set(parsed).where(eq(users.name, 'Jane'));
```

### Refinements

Each create schema function accepts an additional optional parameter that you can used to extend, modify or completely overwite a field's schema. Defining a callback function will extend or modify while providing a arktype schema will overwrite it.

```ts copy
import { pgTable, text, integer, json } from 'drizzle-orm/pg-core';
import { createSelectSchema } from 'drizzle-orm/arktype';
import { ArkErrors, type } from 'arktype';

const users = pgTable('users', {
  id: integer().generatedAlwaysAsIdentity().primaryKey(),
  name: text().notNull(),
  bio: text(),
  preferences: json()
});

const userSelectSchema = createSelectSchema(users, {
  name: (schema) => schema.atMostLength(20), // Extends schema
  bio: () => type.string.atMostLength(2000), // Extends schema before becoming nullable/optional
  preferences: type({ theme: 'string' }) // Overwrites the field, including its nullability
});

const parsed: ArkErrors | {
  id: number;
  name: string,
  bio: string | null;
  preferences: {
    theme: string;
  };
} = userSelectSchema(...);
```

### Data type reference

```ts
pg.boolean();

// Schema
type.boolean;
```

```ts
pgEnum('name', ['val1', 'val2']);

// Schema
type.enumerated('val1', 'val2')
```

```ts
pg.date({ mode: 'date' });
pg.timestamp({ mode: 'date' });

// Schema
type.Date;
```

```ts
pg.date({ mode: 'string' });
pg.timestamp({ mode: 'string' });
pg.cidr();
pg.inet();
pg.interval();
pg.macaddr();
pg.macaddr8();
pg.numeric();
pg.text();
pg.sparsevec();
pg.time();

// Schema
type.string;
```

```ts
pg.bit({ dimensions: ... });

// Schema
type(`/^[01]{${column.dimensions}}$/`);
```

```ts
pg.uuid();

// Schema
type(/^[\da-f]{8}(?:-[\da-f]{4}){3}-[\da-f]{12}$/iu);
```

```ts
pg.char({ length: ... });

// Schema
type.string.exactlyLength(length);
```

```ts
pg.varchar({ length: ... });

// Schema
type.string.atMostLength(length);
```

```ts
pg.text({ enum: ... });
pg.char({ enum: ... });
pg.varchar({ enum: ... });

// Schema
type.enumerated(...enum);
```

```ts
pg.smallint();
pg.smallserial();

// Schema
type.keywords.number.integer.atLeast(-32_768).atMost(32_767); // 16-bit integer lower and upper limit
```

```ts
pg.real();

// Schema
type.number.atLeast(-8_388_608).atMost(8_388_607); // 24-bit integer lower and upper limit
```

```ts
pg.integer();
pg.serial();

// Schema
type.keywords.number.integer.atLeast(-2_147_483_648).atMost(2_147_483_647); // 32-bit integer lower and upper limit
```

```ts
pg.doublePrecision();

// Schema
type.number.atLeast(-140_737_488_355_328).atMost(140_737_488_355_327); // 48-bit integer lower and upper limit
```

```ts
pg.bigint({ mode: 'number' });
pg.bigserial({ mode: 'number' });

// Schema
type.keywords.number.integer.atLeast(-9_007_199_254_740_991).atMost(9_007_199_254_740_991); // Javascript min. and max. safe integers
```

```ts
pg.bigint({ mode: 'bigint' });
pg.bigserial({ mode: 'bigint' });

// Schema
type.bigint.narrow(
  (value, ctx) => value < -9_223_372_036_854_775_808n ? ctx.mustBe('greater than') : value > 9_223_372_036_854_775_807n ? ctx.mustBe('less than') : true
); // 64-bit integer lower and upper limit
```

```ts
pg.geometry({ type: 'point', mode: 'tuple' });
pg.point({ mode: 'tuple' });

// Schema
type([type.number, type.number]);
```

```ts
pg.geometry({ type: 'point', mode: 'xy' });
pg.point({ mode: 'xy' });

// Schema
type({ x: type.number, y: type.number });
```

```ts
pg.halfvec({ dimensions: ... });
pg.vector({ dimensions: ... });

// Schema
type.number.array().exactlyLength(dimensions);
```

```ts
pg.line({ mode: 'abc' });

// Schema
type({ a: type.number, b: type.number, c: type.number });
```

```ts
pg.line({ mode: 'tuple' });

// Schema
type([type.number, type.number, type.number]);
```

```ts
pg.json();
pg.jsonb();

// Schema
type('string | number | boolean | null').or(type('unknown.any[] | Record<string, unknown.any>'));
```

```ts
pg.dataType().array(...);

// Schema
baseDataTypeSchema.array().exactlyLength(size);
```

```ts
pg.bytea();

// Schema
type.unknown.narrow((value) => value instanceof Buffer).as<Buffer>()
```



Source: https://orm.drizzle.team/docs/pg/batch-api

import Section from '@mdx/Section.astro';

# Batch API

Drizzle supports running SQL statements in a batch with the Neon HTTP driver for PostgreSQL.

<Section>
```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),
]);
```

```ts
type BatchResponse = [
  { id: number }[],
  NeonHttpQueryResult,
  { id: number; name: string; verified: number; invitedBy: number | null }[],
  { id: number; name: string; verified: number; invitedBy: number | null }[],
  { id: number; invitedBy: number | null }[],
]
```
</Section>

All possible builders that can be used inside `db.batch`:

```ts
db.query.<table>.findMany(),
db.query.<table>.findFirst(),
db.select()...,
db.update()...,
db.delete()...,
db.insert()...,
```


Source: https://orm.drizzle.team/docs/pg/cache

import Callout from '@mdx/Callout.astro';
import Npm from '@mdx/Npm.astro';

# Cache

Drizzle sends every query straight to your database by default. There are no hidden actions, no automatic caching 
or invalidation - you'll always see exactly what runs. If you want caching, you must opt in.

By default, Drizzle uses a `explicit` caching strategy (i.e. `global: false`), so nothing is ever cached unless you ask. 
This prevents surprises or hidden performance traps in your application. 
Alternatively, you can flip on `all` caching (`global: true`) so that every select will look in cache first.

## Quickstart

### Upstash integration

Drizzle provides an `upstashCache()` helper out of the box. By default, this uses Upstash Redis with automatic configuration if environment variables are set.

```ts
import { upstashCache } from "drizzle-orm/cache/upstash";
import { drizzle } from "drizzle-orm/...";

const db = drizzle(process.env.DB_URL!, {
  cache: upstashCache({ token: process.env.UPSTASH_TOKEN, url: process.env.UPSTASH_URL }),
});
```

You can also explicitly define your Upstash credentials, enable global caching for all queries by default or pass custom caching options:

```ts
import { upstashCache } from "drizzle-orm/cache/upstash";
import { drizzle } from "drizzle-orm/...";

const db = drizzle(process.env.DB_URL!, {
  cache: upstashCache({
    // 👇 Redis credentials (optional — can also be pulled from env vars)
    url: '<UPSTASH_URL>',
    token: '<UPSTASH_TOKEN>',

    // 👇 Enable caching for all queries by default (optional)
    global: true,

    // 👇 Default cache behavior (optional)
    config: { ex: 60 }
  })
});
```

## Cache config reference

Drizzle supports the following cache config options for Upstash:

```ts
export type CacheConfig = {
  /**
   * Expiration in seconds (positive integer)
   */
  ex?: number;
  /**
   * Set an expiration (TTL or time to live) on one or more fields of a given hash key.
   * Used for HEXPIRE command
   */
  hexOptions?: "NX" | "nx" | "XX" | "xx" | "GT" | "gt" | "LT" | "lt";
};
```

## Cache usage examples

Once you've configured caching, here's how the cache behaves:

**Case 1: Drizzle with `global: false` (default, opt-in caching)**

```ts
import { upstashCache } from "drizzle-orm/cache/upstash";
import { drizzle } from "drizzle-orm/...";

const db = drizzle(process.env.DB_URL!, {
  // 👇 `global: true` is not passed, false by default
  cache: upstashCache({ url: "", token: "" }),
});
```

In this case, the following query won't read from cache

```ts
const res = await db.select().from(users);

// Any mutate operation will still trigger the cache's onMutate handler
// and attempt to invalidate any cached queries that involved the affected tables
await db.insert(users).value({ email: "cacheman@upstash.com" });
```

To make this query read from the cache, call `.$withCache()`

```ts
const res = await db.select().from(users).$withCache();
```

`.$withCache` has a set of options you can use to manage and configure this specific query strategy

```ts
// rewrite the config for this specific query
.$withCache({ config: {} })

// give this query a custom cache key (instead of hashing query+params under the hood)
.$withCache({ tag: 'custom_key' })

// turn off auto-invalidation for this query
// note: this leads to eventual consistency (explained below)
.$withCache({ autoInvalidate: false })
```

<Callout>
**Eventual consistency example**

This example is only relevant if you manually set `autoInvalidate: false`. By default, `autoInvalidate` is enabled. 

You might want to turn off `autoInvalidate` if:
- your data doesn't change often, and slight staleness is acceptable (e.g. product listings, blog posts)
- you handle cache invalidation manually

In those cases, turning it off can reduce unnecessary cache invalidation. However, in most cases, we recommend keeping the default enabled.

Example: Imagine you cache the following query on `usersTable` with a 3-second TTL:

``` ts
const recent = await db
  .select().from(usersTable)
  .$withCache({ config: { ex: 3 }, autoInvalidate: false });
```

If someone runs `db.insert(usersTable)...` the cache won't be invalidated immediately. For up to 3 seconds, you'll keep seeing the old data until it eventually becomes consistent.
</Callout>

**Case 2: Drizzle with `global: true` option**

```ts
import { upstashCache } from "drizzle-orm/cache/upstash";
import { drizzle } from "drizzle-orm/...";

const db = drizzle(process.env.DB_URL!, {
  cache: upstashCache({ url: "", token: "", global: true }),
});
```

In this case, the following query will read from cache

```ts
const res = await db.select().from(users);
```

If you want to disable cache for this specific query, call `.$withCache(false)`

```ts
// disable cache for this query
const res = await db.select().from(users).$withCache(false);
```

You can also use cache instance from a `db` to invalidate specific tables or tags

```ts
// Invalidate all queries that use the `users` table. You can do this with the Drizzle instance.
await db.$cache.invalidate({ tables: users });
// or
await db.$cache.invalidate({ tables: [users, posts] });

// Invalidate all queries that use the `usersTable`. You can do this by using just the table name.
await db.$cache.invalidate({ tables: "usersTable" });
// or
await db.$cache.invalidate({ tables: ["usersTable", "postsTable"] });

// You can also invalidate custom tags defined in any previously executed select queries.
await db.$cache.invalidate({ tags: "custom_key" });
// or
await db.$cache.invalidate({ tags: ["custom_key", "custom_key1"] });
```

## Custom cache

This example shows how to plug in a custom `cache` in Drizzle: you provide functions to fetch data from the cache, store results back into cache, and invalidate entries whenever a mutation runs.

Cache extension provides this set of config options
```ts
export type CacheConfig = {
  /** expire time, in seconds */
  ex?: number;
  /** expire time, in milliseconds */
  px?: number;
  /** Unix time (sec) at which the key will expire */
  exat?: number;
  /** Unix time (ms) at which the key will expire */
  pxat?: number;
  /** retain existing TTL when updating a key */
  keepTtl?: boolean;
  /** options for HEXPIRE (hash-field TTL) */
  hexOptions?: 'NX' | 'XX' | 'GT' | 'LT' | 'nx' | 'xx' | 'gt' | 'lt';
};
```

```ts
const db = drizzle(process.env.DB_URL!, { cache: new TestGlobalCache() });
```

```ts
import Keyv from "keyv";

export class TestGlobalCache extends Cache {
  private globalTtl: number = 1000;
  // This object will be used to store which query keys were used
  // for a specific table, so we can later use it for invalidation.
  private usedTablesPerKey: Record<string, string[]> = {};

  constructor(private kv: Keyv = new Keyv()) {
    super();
  }

  // For the strategy, we have two options:
  // - 'explicit': The cache is used only when .$withCache() is added to a query.
  // - 'all': All queries are cached globally.
  // The default behavior is 'explicit'.
  override strategy(): "explicit" | "all" {
    return "all";
  }

  // This function accepts query and parameters that cached into key param,
  // allowing you to retrieve response values for this query from the cache.
  override async get(key: string): Promise<any[] | undefined> {
    const res = (await this.kv.get(key)) ?? undefined;
    return res;
  }

  // This function accepts several options to define how cached data will be stored:
  // - 'key': A hashed query and parameters.
  // - 'response': An array of values returned by Drizzle from the database.
  // - 'tables': An array of tables involved in the select queries. This information is needed for cache invalidation.
  // - 'isTag': A boolean flag indicating whether this cache entry represents a tag-based query.
  //    When true, the entry is associated with a specific tag rather than table-level invalidation,
  //    allowing you to invalidate cached queries by tag name. See the UpstashCache:
  //    https://github.com/drizzle-team/drizzle-orm/blob/beta/drizzle-orm/src/cache/upstash/cache.ts for an example
  //
  // For example, if a query uses the "users" and "posts" tables, you can store this information. Later, when the app executes
  // any mutation statements on these tables, you can remove the corresponding key from the cache.
  // If you're okay with eventual consistency for your queries, you can skip this option.
  override async put(
    key: string,
    response: any,
    tables: string[],
    isTag: boolean = false,
    config?: CacheConfig,
  ): Promise<void> {
    const ttl = config?.px ?? (config?.ex ? config.ex * 1000 : this.globalTtl);

    await this.kv.set(key, response, ttl);

    for (const table of tables) {
      const keys = this.usedTablesPerKey[table];
      if (keys === undefined) {
        this.usedTablesPerKey[table] = [key];
      } else {
        keys.push(key);
      }
    }
  }

  // This function is called when insert, update, or delete statements are executed.
  // You can either skip this step or invalidate queries that used the affected tables.
  //
  // The function receives an object with two keys:
  // - 'tags': Used for queries labeled with a specific tag, allowing you to invalidate by that tag.
  // - 'tables': The actual tables affected by the insert, update, or delete statements,
  //   helping you track which tables have changed since the last cache update.
  override async onMutate(params: {
    tags: string | string[];
    tables: string | string[] | Table<any> | Table<any>[];
  }): Promise<void> {
    const tagsArray = params.tags
      ? Array.isArray(params.tags)
        ? params.tags
        : [params.tags]
      : [];
    const tablesArray = params.tables
      ? Array.isArray(params.tables)
        ? params.tables
        : [params.tables]
      : [];

    const keysToDelete = new Set<string>();

    for (const table of tablesArray) {
      const tableName = is(table, Table)
        ? getTableName(table)
        : (table as string);
      const keys = this.usedTablesPerKey[tableName] ?? [];
      for (const key of keys) keysToDelete.add(key);
    }

    if (keysToDelete.size > 0 || tagsArray.length > 0) {
      for (const tag of tagsArray) {
        await this.kv.delete(tag);
      }

      for (const key of keysToDelete) {
        await this.kv.delete(key);
        for (const table of tablesArray) {
          const tableName = is(table, Table)
            ? getTableName(table)
            : (table as string);
          this.usedTablesPerKey[tableName] = [];
        }
      }
    }
  }
}
```

## Limitations

#### Queries that won't be handled by the `cache` extension:

- Using cache with raw queries, such as:

```ts
db.execute(sql`select 1`);
```

```
- Using cache in transactions
```ts
await db.transaction(async (tx) => {
  await tx.update(accounts).set(...).where(...);
  await tx.update...
});
```

#### Limitations that are temporary and will be handled soon:

- Using cache with Drizzle Relational Queries
```ts
await db.query.users.findMany();
```

- Using cache with AWS Data API drivers
- Using cache with views


Source: https://orm.drizzle.team/docs/pg/codecs

import Section from '@mdx/Section.astro';
import Callout from '@mdx/Callout.astro';

# Codecs

## What are codecs?

Codecs are a driver-aware transform layer that sits between your JavaScript values and the database. They solve the problem of **different drivers returning and accepting data in different formats** for the same column types.

## Why are they needed?

1. **Driver differences** — each PG driver (`node-postgres`, `postgres-js`, `pglite`, etc.) parses and serializes types differently. Codecs normalize these differences so your app code doesn't have to care which driver you're using.

2. **JSON context** — when a column is selected inside a JSON function (like `jsonAgg`, `jsonBuildObject`, or relational queries), the database returns values in JSON format which may differ from the regular format. For example, `bigint` in JSON becomes a number (losing precision). Codecs handle this by casting to text before JSON-ification (`castInJson`) and then parsing it back (`normalizeInJson`).

## How codecs work

Codecs have two layers: **cast** and **normalize**.

```

          ┌───────────────────────────────────────┐
          │  Cast layer (DB level)                │
          │  SELECT "bigint"::text FROM "users"   │
          └───────────────────────────────────────┘
 
          ┌────────────────────────────────────┐
          │  Normalize layer (Code level)      │
          │  "123" → BigInt("123") → 123n      │
          └────────────────────────────────────┘
```

<br/>

**Cast** operates at the database level — it wraps a column in a SQL `::type`

**Normalize** operates at the code level — it transforms the raw value into the  type you/driver expect

<br/>

Both layers can have separate variants for different query contexts:

For reads (SELECT):

```
SQL generation:      SELECT "col"::text FROM ...     ← cast layer modifies SQL
                            ▼
Database executes:   returns text representation
                            ▼
JS result mapping:   parseLineABC(rawValue)          ← normalize layer transforms in JS
                            ▼
Your code gets:      { a: 1, b: 2, c: 3 }
```

For writes (INSERT/UPDATE):

```
Your JS value:       { key: "val" }
                            ▼
JS param building:   JSON.stringify(value)            ← normalize layer transforms in JS
                            ▼
SQL generation:      INSERT ... VALUES ($1::jsonb)    ← cast layer modifies SQL
                            ▼
Database receives:   '{"key":"val"}' with type hint
```

<br/>

Each layer operates across 3 contexts, each with scalar and array variants:

```
                        Cast (SQL)              Normalize (JS)
                   ┌──────────────────┐    ┌──────────────────────┐
  Regular SELECT   │ cast             │    │ normalize            │
                   │ castArray        │    │ normalizeArray       │
                   ├──────────────────┤    ├──────────────────────┤
  Inside JSON      │ castInJson       │    │ normalizeInJson      │
  (jsonAgg, RQB)   │ castArrayInJson  │    │ normalizeArrayInJson │
                   ├──────────────────┤    ├──────────────────────┤
  Params           │ castParam        │    │ normalizeParam       │
  (INSERT/UPDATE)  │ castArrayParam   │    │ normalizeParamArray  │
                   └──────────────────┘    └──────────────────────┘
```

JSON context exists because databases serialize values differently inside JSON — a `bigint` that normally comes back as a string from the driver will come back as a lossy number inside a JSON object. So codecs need separate handling: cast to `::text` in SQL before JSON wrapping, then parse the text back in JS after.

<br/>

| Method | When | Example SQL |
|---|---|:---:|
| `cast` | Column in SELECT | `"col"::text` |
| `castArray` | Array column in SELECT | `"col"::text[]` |
| `castInJson` | Column inside JSON functions | `"col"::text` (inside `json_agg`) |
| `castArrayInJson` | Array column inside JSON | |
| `castParam` | Param placeholder in INSERT/UPDATE/WHERE | `$1::date` |
| `castArrayParam` | Array param placeholder | `$1::date[]` |

<br/>

| Method | When | Example |
|---|---|:---:|
| `normalize` | SELECT result → JS value | `"123"` → `123n` |
| `normalizeArray` | SELECT array result → JS array | `["123", "456"]` → `[123n, 456n]` |
| `normalizeInJson` | SELECT result inside JSON → JS | JSON `bigint` → `BigInt` |
| `normalizeArrayInJson` | SELECT array inside JSON → JS | |
| `normalizeParam` | JS value → driver param (INSERT/UPDATE/WHERE) | `{ key: "val" }` → `'{"key":"val"}'` |
| `normalizeParamArray` | JS array → driver array param | `[1, 2]` → `{1,2}` (PG array literal) |

<br/>

## Are they enabled by default?

Yes. Every driver ships default codecs. When you call `drizzle(client)`, the driver's codecs are automatically used.  
You don't need to do anything to enable them.

## How codecs work in built-in column types

Every built-in PG column class declares a `codec` string identifier:

```ts {3,8,11,14,19,22,27}
// pg-core/columns/integer.ts
class PgInteger extends PgColumn {
  override readonly codec = 'int';
}

// pg-core/columns/bigint.ts  
class PgBigInt53 extends PgColumn {
  override readonly codec = 'bigint:number';
}
class PgBigInt64 extends PgColumn {
  override readonly codec = 'bigint';
}
class PgBigIntString extends PgColumn {
  override readonly codec = 'bigint:string';
}

// pg-core/columns/line.ts
class PgLineABC extends PgColumn {
  override readonly codec = 'line';
}
class PgLineTuple extends PgColumn {
  override readonly codec = 'line:tuple'
}

...
```

This identifier is a lookup key into the driver's codec map. If the driver defines transforms for that key, they're applied. If not, the value passes through untouched.

For example, `integer` has codec `'int'`. The `node-postgres` codec map has **no entry** for `'int'` — integers don't need any transformation. But `bigint` has codec `'bigint'`, and node-postgres defines:

```ts
// node-postgres/codecs.ts
bigint: {
  normalize: BigInt,                           // SELECT: "123" → 123n
  normalizeArray: arrayCompatNormalize(BigInt), // SELECT array: ["123"] → [123n]
}
```

## Overriding codecs for built-in types

Built-in columns (like `integer()`, `bigint()`, `date()`, `text()`, etc.) have a hardcoded `codec` string — you can't change which codec identifier a column uses. But you **can** change what that codec identifier does by overriding the driver's codec map.

Every PG driver accepts a `codecs` option in `drizzle()`:

```ts {3-6}
const db = drizzle(client, {
  codecs: {
    "bigint:number": {
      cast: (name) => sql`${name}::text`,
      normalize: BigInt,
    },
  },
});
```

## How codecs work in `customType()`

<Callout type='info' title='Note'>
`toDriver`/`fromDriver` on `customType` and codecs are **separate layers**. 
`toDriver`/`fromDriver` are per-column instance transforms. Codecs are driver-level transforms and both are applied  
On reads - `codec normalize` first → then `fromDriver`
On writes - `toDriver` first → then `codec normalizeParam`
</Callout>

Read more about custom types [here](/docs/custom-types)

When defining a custom column type, you can specify which codec to use via the `codec` property:

```ts
import { customType } from 'drizzle-orm/pg-core';

// Use an existing codec by name
const customBigint = customType<{ data: bigint; driverData: string }>({
  dataType() {
    return "bigint";
  },
  fromDriver(value: string) {
    return BigInt(Number(value) * 1000); // ← extra column mapping logic
  },
  codec: "bigint", // ← uses the driver's bigint codec
});

// Codec as a function (useful when codec depends on config)
const customDataType = customType<{
  data: number;
  driverData: bigint | number;
  config?: { mode: "bigint" | "number" };
  configRequired: true;
}>({
  dataType() {
    return `custom_type`;
  },
  fromDriver(value: bigint | number) {
    return Number(value) / 1000; // ← extra column mapping logic
  },
  codec: (config) => {
    // ← can be dynamic based on config
    if (!config || config.mode === "bigint") {
      return "bigint";
    }

    return "bigint:number";
  },
});

// No codec — skip codec transforms entirely
const rawCustom = customType<{ data: string; driverData: string }>({
  dataType() {
    return 'my_type';
  },
  // codec is undefined by default — no codec transforms applied
});
```

The `codec` field accepts:
- A `string` — one of the PostgreSQL type identifiers (e.g. `'bigint'`, `'date'`, `'json'`, `'text'`, etc.)
- A `function` `(config) => string | undefined` — dynamically resolve the codec based on the column's config
- `undefined` (default) — no codec, values pass through as-is

Source: https://orm.drizzle.team/docs/pg/column-types


import Section from '@mdx/Section.astro';
import Callout from '@mdx/Callout.astro';

We have native support for all of them, yet if that's not enough for you, feel free to create **[custom types](/docs/custom-types)**.

<Callout title='important' type='warning'>
All examples in this part of the documentation do not use database column name aliases, and column names are generated from TypeScript keys. 

You can use database aliases in column names if you want, and you can also use the `casing API` to define a mapping strategy for Drizzle.
You can read more about it [here](/docs/sql-schema-declaration#shape-your-data-schema)

</Callout>

### integer
`integer` `int` `int4`  
Signed 4-byte integer     

If you need `integer autoincrement` please refer to **[serial.](#serial)**

<Section>
```typescript
import { integer, pgTable } from "drizzle-orm/pg-core";

export const table = pgTable('table', {
	int: integer()
});

```

```sql
CREATE TABLE "table" (
	"int" integer
);
```
</Section>

<Section>
```typescript
import { sql } from "drizzle-orm";
import { integer, pgTable } from "drizzle-orm/pg-core";

export const table = pgTable('table', {
	int1: integer().default(10),
	int2: integer().default(sql`10`)
});

```

```sql
CREATE TABLE "table" (
	"int1" integer DEFAULT 10,
	"int2" integer DEFAULT 10
);
```
</Section>

### smallint
`smallint` `int2`  
Small-range signed 2-byte integer   

If you need `smallint autoincrement` please refer to **[smallserial.](#smallserial)**
<Section>
```typescript
import { smallint, pgTable } from "drizzle-orm/pg-core";

export const table = pgTable('table', {
	smallint: smallint()
});
```

```sql
CREATE TABLE "table" (
	"smallint" smallint
);
```
</Section>

<Section>
```typescript
import { sql } from "drizzle-orm";
import { smallint, pgTable } from "drizzle-orm/pg-core";

export const table = pgTable('table', {
	smallint1: smallint().default(10),
	smallint2: smallint().default(sql`10`)
});
```

```sql
CREATE TABLE "table" (
	"smallint1" smallint DEFAULT 10,
	"smallint2" smallint DEFAULT 10
);
```
</Section>

### bigint
`bigint` `int8`  
Signed 8-byte integer  

If you need `bigint autoincrement` please refer to **[bigserial.](#bigserial)**

If you're expecting values above 2^31 but below 2^53, you can utilise `mode: 'number'` and deal with javascript number as opposed to bigint.
<Section>
```typescript
import { bigint, pgTable } from "drizzle-orm/pg-core";

export const table = pgTable('table', {
	bigint: bigint({ mode: 'number' })
});

// will be inferred as `number`
bigint: bigint({ mode: 'number' })

// will be inferred as `bigint`
bigint: bigint({ mode: 'bigint' })
```

```sql
CREATE TABLE "table" (
	"bigint" bigint
);
```
</Section>

<Section>
```typescript
import { sql } from "drizzle-orm";
import { bigint, pgTable } from "drizzle-orm/pg-core";

export const table = pgTable('table', {
	bigint1: bigint({ mode: "number" }).default(10),
	bigint2: bigint({ mode: "number" }).default(sql`10`),
});
```

```sql
CREATE TABLE "table" (
	"bigint1" bigint DEFAULT 10,
	"bigint2" bigint DEFAULT 10
);
```
</Section>

## ---

### serial
`serial` `serial4`  
Auto incrementing 4-bytes integer, notational convenience for creating unique identifier columns (similar to the `AUTO_INCREMENT` property supported by some other databases). 

For more info please refer to the official PostgreSQL **[docs.](https://www.postgresql.org/docs/current/datatype-numeric.html#DATATYPE-SERIAL)**
<Section>
```typescript
import { serial, pgTable } from "drizzle-orm/pg-core";

export const table = pgTable('table', {
	serial: serial(),
});
```

```sql
CREATE TABLE "table" (
	"serial" serial NOT NULL
);
```
</Section>

### smallserial
`smallserial` `serial2`  
Auto incrementing 2-bytes integer, notational convenience for creating unique identifier columns (similar to the `AUTO_INCREMENT` property supported by some other databases). 

For more info please refer to the official PostgreSQL **[docs.](https://www.postgresql.org/docs/current/datatype-numeric.html#DATATYPE-SERIAL)**
<Section>
```typescript
import { smallserial, pgTable } from "drizzle-orm/pg-core";

export const table = pgTable('table', {
	smallserial: smallserial(),
});
```

```sql
CREATE TABLE "table" (
	"smallserial" smallserial NOT NULL
);
```
</Section>

### bigserial
`bigserial` `serial8`  
Auto incrementing 8-bytes integer, notational convenience for creating unique identifier columns (similar to the `AUTO_INCREMENT` property supported by some other databases).

For more info please refer to the official PostgreSQL **[docs.](https://www.postgresql.org/docs/current/datatype-numeric.html#DATATYPE-SERIAL)**

If you're expecting values above 2^31 but below 2^53, you can utilise `mode: 'number'` and deal with javascript number as opposed to bigint.
<Section>
```typescript
import { bigserial, pgTable } from "drizzle-orm/pg-core";

export const table = pgTable('table', {
	bigserial: bigserial({ mode: 'number' }),
});
```

```sql
CREATE TABLE "table" (
	"bigserial" bigserial NOT NULL
);
```
</Section>

### ---

### boolean
PostgreSQL provides the standard SQL type boolean.

For more info please refer to the official PostgreSQL **[docs.](https://www.postgresql.org/docs/current/datatype-boolean.html)**

<Section>
```typescript
import { boolean, pgTable } from "drizzle-orm/pg-core";

export const table = pgTable('table', {
	boolean: boolean(),
	boolean1: boolean().default(true),
	boolean2: boolean().default(sql`true`),
});

```

```sql
CREATE TABLE "table" (
	"boolean" boolean,
	"boolean1" boolean DEFAULT true,
	"boolean2" boolean DEFAULT true
);
```
</Section>

## ---

### bytea

PostgreSQL provides the standard SQL type bytea.

For more info please refer to the official PostgreSQL **[docs.](https://www.postgresql.org/docs/current/datatype-binary.html)**

<Section>
```typescript
import { bytea, pgTable } from "drizzle-orm/pg-core";

export const table = pgTable('table', {
	bytea: bytea()
});

```

```sql
CREATE TABLE "table" (
	"bytea" bytea,
);
```
</Section>

## ---

### text
`text`  
Variable-length(unlimited) character string.

For more info please refer to the official PostgreSQL **[docs.](https://www.postgresql.org/docs/current/datatype-character.html)**
  
You can define `{ enum: ["value1", "value2"] }` config to infer `insert` and `select` types, it **won't** check runtime values.
<Section>
```typescript
import { text, pgTable } from "drizzle-orm/pg-core";

export const table = pgTable('table', {
	text: text()
});

// will be inferred as text: "value1" | "value2" | null
text: text({ enum: ["value1", "value2"] })
```

```sql
CREATE TABLE "table" (
	"text" text
);
```
</Section>

### varchar
`character varying(n)` `varchar(n)`  
Variable-length character string, can store strings up to **`n`** characters (not bytes). 

For more info please refer to the official PostgreSQL **[docs.](https://www.postgresql.org/docs/current/datatype-character.html)**

You can define `{ enum: ["value1", "value2"] }` config to infer `insert` and `select` types, it **won't** check runtime values.

The `length` parameter is optional according to PostgreSQL docs.
<Section>
```typescript
import { varchar, pgTable } from "drizzle-orm/pg-core";

export const table = pgTable('table', {
	varchar1: varchar(),
	varchar2: varchar({ length: 256 }),
});

// will be inferred as text: "value1" | "value2" | null
varchar: varchar({ enum: ["value1", "value2"] }),
```

```sql
CREATE TABLE "table" (
	"varchar1" varchar,
	"varchar2" varchar(256)
);
```
</Section>

### char
`character(n)` `char(n)`  
Fixed-length, blank padded character string, can store strings up to **`n`** characters(not bytes).

For more info please refer to the official PostgreSQL **[docs.](https://www.postgresql.org/docs/current/datatype-character.html)**

You can define `{ enum: ["value1", "value2"] }` config to infer `insert` and `select` types, it **won't** check runtime values.

The `length` parameter is optional according to PostgreSQL docs.
<Section>
```typescript
import { char, pgTable } from "drizzle-orm/pg-core";

export const table = pgTable('table', {
	char1: char(),
	char2: char({ length: 256 }),
});

// will be inferred as text: "value1" | "value2" | null
char: char({ enum: ["value1", "value2"] }),
```

```sql
CREATE TABLE "table" (
	"char1" char,
	"char2" char(256)
);
```
</Section>

## ---

### numeric
`numeric` `decimal`  
Exact numeric of selectable precision. Can store numbers with a very large number of digits, up to 131072 digits before the decimal point and up to 16383 digits after the decimal point.

For more info please refer to the official PostgreSQL **[docs.](https://www.postgresql.org/docs/current/datatype-numeric.html#DATATYPE-NUMERIC-DECIMAL)**

<Section>
```typescript
import { numeric, pgTable } from "drizzle-orm/pg-core";

export const table = pgTable('table', {
	numeric1: numeric(),
	numeric2: numeric({ precision: 100 }),
	numeric3: numeric({ precision: 100, scale: 20 }),
	numericNum: numeric({ mode: 'number' }),
	numericBig: numeric({ mode: 'bigint' }),
});
```

```sql
CREATE TABLE "table" (
	"numeric1" numeric,
	"numeric2" numeric(100),
	"numeric3" numeric(100, 20),
	"numericNum" numeric,
	"numericBig" numeric
);
```
</Section>

### decimal
An alias of **[numeric.](#numeric)**

### real
`real` `float4`  
Single precision floating-point number (4 bytes)

For more info please refer to the official PostgreSQL **[docs.](https://www.postgresql.org/docs/current/datatype-numeric.html)**  

<Section>
```typescript
import { sql } from "drizzle-orm";
import { real, pgTable } from "drizzle-orm/pg-core";  

export const table = pgTable('table', {
	real1: real(),
	real2: real().default(10.1),
	real3: real().default(sql`10.1`),
});
```

```sql
CREATE TABLE "table" (
	"real1" real,
	"real2" real DEFAULT 10.1,
	"real3" real DEFAULT 10.1
);
```
</Section>

### double precision
`double precision` `float8`  
Double precision floating-point number (8 bytes)

For more info please refer to the official PostgreSQL **[docs.](https://www.postgresql.org/docs/current/datatype-numeric.html)**  

<Section>
```typescript
import { sql } from "drizzle-orm";
import { doublePrecision, pgTable } from "drizzle-orm/pg-core";

export const table = pgTable('table', {
	double1: doublePrecision(),
	double2: doublePrecision().default(10.1),
	double3: doublePrecision().default(sql`10.1`),
});
```

```sql
CREATE TABLE "table3" (
	"double1" double precision,
	"double2" double precision DEFAULT 10.1,
	"double3" double precision DEFAULT 10.1
);
```
</Section>

## ---


### json
`json`  
Textual JSON data, as specified in **[RFC 7159.](https://tools.ietf.org/html/rfc7159)**

For more info please refer to the official PostgreSQL **[docs.](https://www.postgresql.org/docs/current/datatype-json.html)**
<Section>
```typescript
import { sql } from "drizzle-orm";
import { json, pgTable } from "drizzle-orm/pg-core";

export const table = pgTable('table', {
	json1: json(),
	json2: json().default({ foo: "bar" }),
	json3: json().default(sql`'{"foo": "bar"}'`),
});
```

```sql
CREATE TABLE "table" (
	"json1" json,
	"json2" json DEFAULT '{"foo":"bar"}',
	"json3" json DEFAULT '{"foo": "bar"}'
);
```
</Section>
  
You can specify `.$type<..>()` for json object inference, it **won't** check runtime values. 
It provides compile time protection for default values, insert and select schemas.
```typescript
// will be inferred as { foo: string }
json: json().$type<{ foo: string }>();

// will be inferred as string[]
json: json().$type<string[]>();

// won't compile
json: json().$type<string[]>().default({});
```

### jsonb
`jsonb`  
Binary JSON data, decomposed.

For more info please refer to the official PostgreSQL **[docs.](https://www.postgresql.org/docs/current/datatype-json.html)**
<Section>
```typescript
import { jsonb, pgTable } from "drizzle-orm/pg-core";

export const table = pgTable('table', {
	jsonb1: jsonb(),
	jsonb2: jsonb().default({ foo: "bar" }),
	jsonb3: jsonb().default(sql`'{"foo": "bar"}'`),
});
```
```sql
CREATE TABLE "table" (
	"jsonb1" jsonb,
	"jsonb2" jsonb DEFAULT '{"foo":"bar"}',
	"jsonb3" jsonb DEFAULT '{"foo": "bar"}'
);
```
</Section>

You can specify `.$type<..>()` for json object inference, it **won't** check runtime values. 
It provides compile time protection for default values, insert and select schemas.

```typescript
// will be inferred as { foo: string }
jsonb: jsonb().$type<{ foo: string }>();

// will be inferred as string[]
jsonb: jsonb().$type<string[]>();

// won't compile
jsonb: jsonb().$type<string[]>().default({});
```

## ---

### uuid
`uuid`

The data type uuid stores Universally Unique Identifiers (UUID) as defined by RFC 4122, ISO/IEC 9834-8:2005, and related standards

For more info please refer to the official PostgreSQL **[docs.](https://www.postgresql.org/docs/current/datatype-uuid.html)**

```ts
import { uuid, pgTable } from "drizzle-orm/pg-core";

export const table = pgTable('table', {
	uuid1: uuid(),
	uuid2: uuid().defaultRandom(),
	uuid3: uuid().default('a0ee-bc99-9c0b-4ef8-bb6d-6bb9-bd38-0a11')
});
```

```sql
CREATE TABLE "table" (
	"uuid1" uuid,
	"uuid2" uuid DEFAULT gen_random_uuid(),
	"uuid3" uuid DEFAULT 'a0ee-bc99-9c0b-4ef8-bb6d-6bb9-bd38-0a11'
);
```

## ---

### time
`time` `timetz` `time with timezone` `time without timezone`  
Time of day with or without time zone.

For more info please refer to the official PostgreSQL **[docs.](https://www.postgresql.org/docs/current/datatype-datetime.html)**

<Section>
```typescript
import { time, pgTable } from "drizzle-orm/pg-core";

export const table = pgTable('table', {
	time1: time(),
	time2: time({ withTimezone: true }),
	time3: time({ precision: 6 }),
	time4: time({ precision: 6, withTimezone: true })
});
```

```sql
CREATE TABLE "table" (
	"time1" time,
	"time2" time with time zone,
	"time3" time(6),
	"time4" time(6) with time zone
);
```
</Section>

### timestamp
`timestamp` `timestamptz` `timestamp with time zone` `timestamp without time zone`  
Date and time with or without time zone.

For more info please refer to the official PostgreSQL **[docs.](https://www.postgresql.org/docs/current/datatype-datetime.html)**
<Section>
```typescript
import { sql } from "drizzle-orm";
import { timestamp, pgTable } from "drizzle-orm/pg-core";

export const table = pgTable('table', {
	timestamp1: timestamp(),
	timestamp2: timestamp({ precision: 6, withTimezone: true }),
	timestamp3: timestamp().defaultNow(),
	timestamp4: timestamp().default(sql`now()`),
});
```
```sql
CREATE TABLE "table" (
	"timestamp1" timestamp,
	"timestamp2" timestamp(6) with time zone,
	"timestamp3" timestamp DEFAULT now(),
	"timestamp4" timestamp DEFAULT now()
);
```
</Section>

You can specify either `date` or `string` infer modes:
```typescript
// will infer as date
timestamp: timestamp({ mode: "date" }),

// will infer as string
timestamp: timestamp({ mode: "string" }),
```

> The `string` mode does not perform any mappings for you. This mode was added to Drizzle ORM to provide developers
with the possibility to handle dates and date mappings themselves, depending on their needs.
Drizzle will pass raw dates as strings `to` and `from` the database, so the behavior should be as predictable as possible 
and aligned 100% with the database behavior

> The `date` mode is the regular way to work with dates. Drizzle will take care of all mappings between the database and the JS Date object

<Callout type='info' emoji='ℹ️'>
 How mapping works for `timestamp` and `timestamp with timezone`:

 As PostgreSQL docs stated:
 > In a literal that has been determined to be timestamp without time zone, PostgreSQL will silently ignore any time zone indication. 
 > That is, the resulting value is derived from the date/time fields in the input value, and is not adjusted for time zone.
 >
 > For timestamp with time zone, the internally stored value is always in UTC (Universal Coordinated Time, traditionally known as Greenwich Mean Time, GMT). 
 An input value that has an explicit time zone specified is converted to UTC using the appropriate offset for that time zone. 
 If no time zone is stated in the input string, then it is assumed to be in the time zone indicated by the system's TimeZone parameter, 
 and is converted to UTC using the offset for the timezone zone.

 So for `timestamp with timezone` you will get back string converted to a timezone set in your Postgres instance. 
 You can check timezone using this sql query: 
 
 ```sql 
 show timezone;
 ```


</Callout>

### date
`date`  
Calendar date (year, month, day)

For more info please refer to the official PostgreSQL **[docs.](https://www.postgresql.org/docs/current/datatype-datetime.html)**
<Section>
```typescript
import { date, pgTable } from "drizzle-orm/pg-core";

export const table = pgTable('table', {
	date: date(),
});
```

```sql
CREATE TABLE "table" (
	"date" date
);
```
</Section>
You can specify either `date` or `string` infer modes:
```typescript
// will infer as date
date: date({ mode: "date" }),

// will infer as string
date: date({ mode: "string" }),
```
### interval
`interval`  
Time span

For more info please refer to the official PostgreSQL **[docs.](https://www.postgresql.org/docs/current/datatype-datetime.html)** 

<Section>
```typescript
import { interval, pgTable } from "drizzle-orm/pg-core";

export const table = pgTable('table', {
	interval1: interval(),
	interval2: interval({ fields: "day to second", precision: 6 }),
	interval3: interval({ fields: "month" })
});

```

```sql
CREATE TABLE "table" (
	"interval1" interval,
	"interval2" interval day to second(6),
	"interval3" interval month
);
```
</Section>

## ---

### point
`point`  
Geometric point type

For more info please refer to the official PostgreSQL **[docs.](https://www.postgresql.org/docs/current/datatype-geometric.html#DATATYPE-GEOMETRIC-POINTS)** 

Type `point` has 2 modes for mappings from the database: `tuple` and `xy`.

- `tuple` will be accepted for insert and mapped on select to a tuple. So, the database Point(1,2) will be typed as [1,2] with drizzle.

- `xy` will be accepted for insert and mapped on select to an object with x, y coordinates. So, the database Point(1,2) will be typed as `{ x: 1, y: 2 }` with drizzle

<Section>
```typescript
export const items = pgTable('items', {
	point: point(),
	pointObj: point({ mode: 'xy' }),
});
```

```sql
CREATE TABLE "items" (
	"point" point,
	"pointObj" point
);
```
</Section>

### line
`line`  
Geometric line type

For more info please refer to the official PostgreSQL **[docs.](https://www.postgresql.org/docs/current/datatype-geometric.html#DATATYPE-LINE)** 

Type `line` has 2 modes for mappings from the database: `tuple` and `abc`.

- `tuple` will be accepted for insert and mapped on select to a tuple. So, the database Line `{1,2,3}` will be typed as `[1,2,3]` with drizzle.

- `abc` will be accepted for insert and mapped on select to an object with a, b, and c constants from the equation `Ax + By + C = 0`. So, the database Line `{1,2,3}` will be typed as `{ a: 1, b: 2, c: 3 }` with drizzle.

<Section>
```typescript
export const items = pgTable('items', {
	line: line(),
	lineObj: line({ mode: 'abc' }),
});
```

```sql
CREATE TABLE "items" (
	"line" line,
	"lineObj" line
);
```
</Section>

## ---

### enum 
`enum` `enumerated types`  
Enumerated (enum) types are data types that comprise a static, ordered set of values. 
They are equivalent to the enum types supported in a number of programming languages. 
An example of an enum type might be the days of the week, or a set of status values for a piece of data.

For more info please refer to the official PostgreSQL **[docs.](https://www.postgresql.org/docs/current/datatype-enum.html)**
<Section>
```typescript
import { pgEnum, pgTable } from "drizzle-orm/pg-core";

export const moodEnum = pgEnum('mood', ['sad', 'ok', 'happy']);

export const table = pgTable('table', {
	mood: moodEnum(),
});
```

```sql
CREATE TYPE mood AS ENUM ('sad', 'ok', 'happy');

CREATE TABLE "table" (
	"mood" "mood"
);
```
</Section>

## ---

### inet
`inet`  
The `inet` type holds an IPv4 or IPv6 host address, and optionally its subnet, all in one field

For more info please refer to the official PostgreSQL **[docs.](https://www.postgresql.org/docs/current/datatype-net-types.html#DATATYPE-INET)**

<Section>
```typescript
import { inet, pgTable } from "drizzle-orm/pg-core";

export const table = pgTable('table', {
	inet: inet(),
	inet2: inet().default('127.0.0.1')
});
```

```sql
CREATE TABLE "table" (
	"inet" inet,
	"inet2" inet DEFAULT '127.0.0.1'
);
```
</Section>

### cidr
`cidr`  
The `cidr` type holds an IPv4 or IPv6 network specification

For more info please refer to the official PostgreSQL **[docs.](https://www.postgresql.org/docs/current/datatype-net-types.html#DATATYPE-CIDR)**

<Section>
```typescript
import { cidr, pgTable } from "drizzle-orm/pg-core";

export const table = pgTable('table', {
	cidr: cidr(),
	cidr2: cidr().default('127.0.0.1/32')
});
```

```sql
CREATE TABLE "table" (
	"cidr" cidr,
	"cidr2" cidr DEFAULT '127.0.0.1/32'
);
```
</Section>

### macaddr
`macaddr`  
The `macaddr` type stores MAC (Media Access Control) address

For more info please refer to the official PostgreSQL **[docs.](https://www.postgresql.org/docs/current/datatype-net-types.html#DATATYPE-MACADDR)**

<Section>
```typescript
import { macaddr, pgTable } from "drizzle-orm/pg-core";

export const table = pgTable('table', {
	macaddr: macaddr(),
	macaddr2: macaddr().default('08:00:2b:01:02:03')
});
```

```sql
CREATE TABLE "table" (
	"macaddr" macaddr,
	"macaddr2" macaddr DEFAULT '08:00:2b:01:02:03'
);
```
</Section>

### macaddr8
`macaddr8`  
The `macaddr8` type stores MAC addresses in EUI-64 format

For more info please refer to the official PostgreSQL **[docs.](https://www.postgresql.org/docs/current/datatype-net-types.html#DATATYPE-MACADDR8)**

<Section>
```typescript
import { macaddr8, pgTable } from "drizzle-orm/pg-core";

export const table = pgTable('table', {
	macaddr8: macaddr8(),
	macaddr8_2: macaddr8().default('08:00:2b:01:02:03:04:05')
});
```

```sql
CREATE TABLE "table" (
	"macaddr8" macaddr8,
	"macaddr8_2" macaddr8 DEFAULT '08:00:2b:01:02:03:04:05'
);
```
</Section>

## ---

### Customizing data type
Every column builder has a `.$type()` method, which allows you to customize the data type of the column. 

This is useful, for example, with unknown or branded types:
```ts
type UserId = number & { __brand: 'user_id' };
type Data = {
	foo: string;
	bar: number;
};

export const users = pgTable('users', {
	id: serial().$type<UserId>().primaryKey(),
	jsonField: json().$type<Data>(),
});
```

### Identity Columns

PostgreSQL supports identity columns as a way to automatically generate unique integer values for a column. These values are generated using sequences and can be defined using the GENERATED AS IDENTITY clause.

**Types of Identity Columns**
- `GENERATED ALWAYS AS IDENTITY`: The database always generates a value for the column. Manual insertion or updates to this column are not allowed unless the OVERRIDING SYSTEM VALUE clause is used.
- `GENERATED BY DEFAULT AS IDENTITY`: The database generates a value by default, but manual values can also be inserted or updated. If a manual value is provided, it will be used instead of the system-generated value.

**Key Features**
- Automatic Value Generation: Utilizes sequences to generate unique values for each new row.
- Customizable Sequence Options: You can define starting values, increments, and other sequence options.
- Support for Multiple Identity Columns: PostgreSQL allows more than one identity column per table.

**Limitations**
- Manual Insertion Restrictions: For columns defined with GENERATED ALWAYS AS IDENTITY, manual insertion or updates require the OVERRIDING SYSTEM VALUE clause.
- Sequence Constraints: Identity columns depend on sequences, which must be managed correctly to avoid conflicts or gaps.

**Usage example**
```ts
import { pgTable, integer, text } from 'drizzle-orm/pg-core' 

export const ingredients = pgTable('ingredients', {
	id: integer().primaryKey().generatedAlwaysAsIdentity({ startWith: 1000 }),
	name: text().notNull(),
	description: text(),
});
```

You can specify all properties available for sequences in the `.generatedAlwaysAsIdentity()` function. Additionally, you can specify custom names for these sequences

PostgreSQL docs [reference](https://www.postgresql.org/docs/current/sql-createtable.html#SQL-CREATETABLE-PARMS-GENERATED-IDENTITY).

### Default value
The `DEFAULT` clause specifies a default value to use for the column if no value
is explicitly provided by the user when doing an `INSERT`.
If there is no explicit `DEFAULT` clause attached to a column definition,
then the default value of the column is `NULL`.

An explicit `DEFAULT` clause may specify that the default value is `NULL`,
a string constant, a blob constant, a signed-number, or any constant expression enclosed in parentheses.

<Section>
```typescript
import { sql } from "drizzle-orm";
import { integer, pgTable, uuid } from "drizzle-orm/pg-core";

export const table = pgTable('table', {
	integer1: integer().default(42),
	integer2: integer().default(sql`42`),
	uuid1: uuid().defaultRandom(),
	uuid2: uuid().default(sql`gen_random_uuid()`),
});
```

```sql
CREATE TABLE "table" (
	"integer1" integer DEFAULT 42,
	"integer2" integer DEFAULT 42,
	"uuid1" uuid DEFAULT gen_random_uuid(),
	"uuid2" uuid DEFAULT gen_random_uuid()
);
```
</Section>

When using `$default()` or `$defaultFn()`, which are simply different aliases for the same function, 
you can generate defaults at runtime and use these values in all insert queries. 

These functions can assist you in utilizing various implementations such as `uuid`, `cuid`, `cuid2`, and many more.

<Callout type="info" emoji="ℹ️">
	Note: This value does not affect the `drizzle-kit` behavior, it is only used at runtime in `drizzle-orm`
</Callout>

```ts
import { text, pgTable } from "drizzle-orm/pg-core";
import { createId } from '@paralleldrive/cuid2';

export const table = pgTable('table', {
	id: text().$defaultFn(() => createId()),
});
```

When using `$onUpdate()` or `$onUpdateFn()`, which are simply different aliases for the same function, 
you can generate defaults at runtime and use these values in all update queries. 

Adds a dynamic update value to the column. The function will be called when the row is updated, 
and the returned value will be used as the column value if none is provided.
If no default (or $defaultFn) value is provided, the function will be called
when the row is inserted as well, and the returned value will be used as the column value.

<Callout type="info" emoji="ℹ️">
	Note: This value does not affect the `drizzle-kit` behavior, it is only used at runtime in `drizzle-orm`
</Callout>

```ts
import { integer, timestamp, text, pgTable } from "drizzle-orm/pg-core";

export const table = pgTable('table', {
	updateCounter: integer().default(sql`1`).$onUpdateFn((): SQL => sql`${table.update_counter} + 1`),
	updatedAt: timestamp({ mode: 'date', precision: 3 }).$onUpdate(() => new Date()),
	alwaysNull: text().$type<string | null>().$onUpdate(() => null),
});
```


### Not null
`NOT NULL` constraint dictates that the associated column may not contain a `NULL` value.

<Section>
```typescript
import { integer, pgTable } from "drizzle-orm/pg-core";

export const table = pgTable('table', {
	integer: integer().notNull(),
});
```

```sql
CREATE TABLE "table" (
	"integer" integer NOT NULL
);
```
</Section>


### Primary key
A primary key constraint indicates that a column, or group of columns, can be used as a unique identifier for rows in the table. 
This requires that the values be both unique and not null.
<Section>
```typescript
import { serial, pgTable } from "drizzle-orm/pg-core";

export const table = pgTable('table', {
	id: serial().primaryKey(),
});
```

```sql
CREATE TABLE "table" (
	"id" serial PRIMARY KEY
);
```
</Section>


Source: https://orm.drizzle.team/docs/pg/connect-appwrite-postgres

import Tab from '@mdx/Tab.astro';
import Tabs from '@mdx/Tabs.astro';
import Npm from "@mdx/Npm.astro";
import Callout from '@mdx/Callout.astro';
import Steps from '@mdx/Steps.astro';
import AnchorCards from '@mdx/AnchorCards.astro';
import Prerequisites from "@mdx/Prerequisites.astro";
import CodeTabs from "@mdx/CodeTabs.astro";
import Section from "@mdx/Section.astro";
import WhatsNextPostgres from "@mdx/WhatsNextPostgres.astro";

# Drizzle \<\> Appwrite Postgres
<Prerequisites>
- Database [connection basics](/docs/connect-overview) with Drizzle
- Appwrite native PostgreSQL database - [website](https://appwrite.io) & [docs](https://appwrite.io/docs/products/databases/postgresql)
- Appwrite PostgreSQL connections - [docs](https://appwrite.io/docs/products/databases/postgresql/connections)
- Drizzle PostgreSQL drivers - [docs](/docs/get-started-postgresql)
</Prerequisites>

Appwrite offers dedicated, native PostgreSQL databases that you connect to directly over TLS. There is no Appwrite-specific driver or abstraction layer, so you can use Drizzle with either the [`node-postgres`](https://node-postgres.com/) or [`postgres.js`](https://github.com/porsager/postgres) driver, the same way you would with any PostgreSQL server.

To get your connection string, open your database in the Appwrite Console and click **Credentials**. The **Drizzle** tab contains a ready-made snippet, and the **DSN** and **.env** tabs contain the raw connection string. You can also fetch it from the Appwrite API with `postgresql.get()`. The connection string already includes `sslmode=require`, so no extra TLS configuration is needed.

```env
DATABASE_URL="postgresql://admin:<password>@db-<hash>.<region>.appwrite.center:5432/<database>?sslmode=require"
```

#### Step 1 - Install packages
<CodeTabs items={["node-postgres (pg)", "postgres.js"]}>
<Npm>
 drizzle-orm@rc pg
 -D drizzle-kit@rc
</Npm>

<Npm>
 drizzle-orm@rc postgres
 -D drizzle-kit@rc
</Npm>

</CodeTabs>

#### Step 2 - Initialize the driver and make a query
<CodeTabs items={["node-postgres (pg)", "postgres.js"]}>
```typescript
// Make sure to install the 'pg' package
import { drizzle } from 'drizzle-orm/node-postgres';

const db = drizzle(process.env.DATABASE_URL);

const result = await db.execute('select 1');
```
```typescript
// Make sure to install the 'postgres' package
import { drizzle } from 'drizzle-orm/postgres-js';

const db = drizzle(process.env.DATABASE_URL);

const result = await db.execute('select 1');
```
</CodeTabs>

If you need to provide your existing drivers:

<CodeTabs items={["node-postgres (pg)", "postgres.js"]}>
```typescript
// Make sure to install the 'pg' package
import { drizzle } from "drizzle-orm/node-postgres";
import { Pool } from "pg";

const pool = new Pool({
  connectionString: process.env.DATABASE_URL,
});
const db = drizzle({ client: pool });

const result = await db.execute('select 1');
```
```typescript
// Make sure to install the 'postgres' package
import { drizzle } from 'drizzle-orm/postgres-js';
import postgres from 'postgres';

const queryClient = postgres(process.env.DATABASE_URL);
const db = drizzle({ client: queryClient });

const result = await db.execute('select 1');
```
</CodeTabs>

#### Connection pooling for serverless

Appwrite runs a [connection pooler](https://appwrite.io/docs/products/databases/postgresql/connection-pooling) on port `6432` of the same hostname. In serverless and edge environments, route your application traffic through the pooler so short-lived instances don't exhaust the engine's connection limit, and keep Drizzle Kit pointed at the direct engine port `5432`, because migrations issue DDL that needs a session-level connection.

```env
# Runtime: pooled, transaction mode
DATABASE_URL="postgresql://admin:<password>@db-<hash>.<region>.appwrite.center:6432/<database>?sslmode=require"

# Migrations & introspection: direct connection to the engine
DIRECT_URL="postgresql://admin:<password>@db-<hash>.<region>.appwrite.center:5432/<database>?sslmode=require"
```

```typescript copy filename="drizzle.config.ts"
import { defineConfig } from 'drizzle-kit';

export default defineConfig({
  dialect: 'postgresql',
  schema: './src/schema.ts',
  out: './drizzle',
  dbCredentials: {
    url: process.env.DIRECT_URL!,
  },
});
```

<Callout type="warning" emoji="⚙️">
The pooler defaults to **transaction mode**, which does not keep a backend connection across statements, so server-side prepared statements are unavailable. With `postgres.js`, build the client yourself with `prepare: false` when connecting through the pooler:

```typescript
import { drizzle } from 'drizzle-orm/postgres-js';
import postgres from 'postgres';

const queryClient = postgres(process.env.DATABASE_URL, { prepare: false });
const db = drizzle({ client: queryClient });
```

If you rely on prepared statements, advisory locks, `LISTEN`/`NOTIFY`, temporary tables or `SET LOCAL`, switch the pooler to session mode or use the direct port.
</Callout>

#### What's next?

<WhatsNextPostgres/>


Source: https://orm.drizzle.team/docs/pg/connect-aws-data-api-pg

import Tab from '@mdx/Tab.astro';
import Tabs from '@mdx/Tabs.astro';
import Npm from "@mdx/Npm.astro";
import Callout from '@mdx/Callout.astro';
import WhatsNextPostgres from "@mdx/WhatsNextPostgres.astro";
import Prerequisites from "@mdx/Prerequisites.astro";
import CodeTabs from "@mdx/CodeTabs.astro";

# Drizzle \<\> AWS Data API Postgres

<Prerequisites>
- Database [connection basics](/docs/connect-overview) with Drizzle
- AWS Data API - [website](https://docs.aws.amazon.com/AmazonRDS/latest/AuroraUserGuide/data-api.html)
- AWS SDK - [website](https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/Package/-aws-sdk-client-rds-data/)
</Prerequisites>

#### Step 1 - Install packages
<Npm>
 drizzle-orm@rc @aws-sdk/client-rds-data
 -D drizzle-kit@rc
</Npm>

#### Step 2 - Initialize the driver and make a query
```typescript copy
import { drizzle } from 'drizzle-orm/aws-data-api/pg';

// These three properties are required. You can also specify
// any property from the RDSDataClient type inside the connection object.
const db = drizzle({ connection: {
  database: process.env['DATABASE']!,
  secretArn: process.env['SECRET_ARN']!,
  resourceArn: process.env['RESOURCE_ARN']!,
}});

await db.select().from(...);
```

If you need to provide your existing driver:

```typescript copy
import { drizzle } from 'drizzle-orm/aws-data-api/pg';
import { RDSDataClient } from '@aws-sdk/client-rds-data';

const rdsClient = new RDSDataClient({ region: 'us-east-1' });

const db = drizzle({
  client: rdsClient,
  database: process.env['DATABASE']!,
  secretArn: process.env['SECRET_ARN']!,
  resourceArn: process.env['RESOURCE_ARN']!,
});

await db.select().from(...);
```

#### What's next?

<WhatsNextPostgres/>


Source: https://orm.drizzle.team/docs/pg/connect-bun-sql

import Npm from "@mdx/Npm.astro";
import Callout from '@mdx/Callout.astro';
import AnchorCards from '@mdx/AnchorCards.astro';
import Steps from '@mdx/Steps.astro';
import WhatsNextPostgres from "@mdx/WhatsNextPostgres.astro";
import Prerequisites from "@mdx/Prerequisites.astro";
import CodeTabs from "@mdx/CodeTabs.astro";

# Drizzle \<\> Bun SQL

<Prerequisites>
- Database [connection basics](/docs/connect-overview) with Drizzle
- Bun - [website](https://bun.sh/docs)
- Bun SQL - native bindings for working with PostgreSQL databases - [read here](https://bun.sh/docs/api/sql)
</Prerequisites>

According to the **[official website](https://bun.sh/)**, Bun is a fast all-in-one JavaScript runtime. 

Drizzle ORM natively supports **[`bun sql`](https://bun.sh/docs/api/sql)** module and it's crazy fast 🚀  

#### Step 1 - Install packages
<Npm>
 drizzle-orm@rc
 -D drizzle-kit@rc
</Npm>

#### Step 2 - Initialize the driver and make a query
```typescript copy
import 'dotenv/config';
import { drizzle } from 'drizzle-orm/bun-sql';

const db = drizzle(process.env.DATABASE_URL);

const result = await db.select().from(...);
```

If you need to provide your existing driver:
```typescript copy
import 'dotenv/config';
import { drizzle } from 'drizzle-orm/bun-sql';
import { SQL } from 'bun';

const client = new SQL(process.env.DATABASE_URL!);
const db = drizzle({ client });
```

#### What's next?

<WhatsNextPostgres/>


Source: https://orm.drizzle.team/docs/pg/connect-drizzle-proxy

import Npm from "@mdx/Npm.astro";
import Callout from '@mdx/Callout.astro';
import Steps from '@mdx/Steps.astro';
import AnchorCards from '@mdx/AnchorCards.astro';
import Prerequisites from "@mdx/Prerequisites.astro";
import Section from "@mdx/Section.astro";

# Drizzle HTTP proxy

<Prerequisites>
- Database [connection basics](/docs/connect-overview) with Drizzle
</Prerequisites>

How an HTTP Proxy works and why you might need it

Drizzle Proxy is used when you need to implement your own driver communication with the database. 
It can be used in several cases, such as adding custom logic at the query stage with existing drivers. 
The most common use is with an HTTP driver, which sends queries to your server with the database, executes the query 
on your database, and responds with raw data that Drizzle ORM can then map to results

<Callout collapsed="How it works under the hood?">
```                                  
┌───────────────────────────┐                 ┌─────────────────────────────┐              
│       Drizzle ORM         │                 │  HTTP Server with Database  │             
└─┬─────────────────────────┘                 └─────────────────────────┬───┘             
  │                                                ^                    │
  │-- 1. Build query         2. Send built query --│                    │
  │                                                │                    │
  │              ┌───────────────────────────┐     │                    │
  └─────────────>│                           │─────┘                    │ 
                 │      HTTP Proxy Driver    │                          │
  ┌──────────────│                           │<─────────────┬───────────┘
  │              └───────────────────────────┘              │
  │                                                  3. Execute a query + send raw results back
  │-- 4. Map data and return        
  │                   
  v
```
</Callout>

Drizzle ORM also supports simply using asynchronous callback function for executing SQL.

- `sql` is a query string with placeholders.
- `params` is an array of parameters.
- One of the following values will set for `method` depending on the SQL statement - `all`, `execute`.

Drizzle always waits for `{rows: string[][]}` or `{rows: string[]}` for the return value.

- When the `method` is `execute`, you should return a value as `{rows: string[]}`.
- Otherwise, you should return `{rows: string[][]}`.

<br/>

<Section>
```typescript copy
// Example of driver implementation
import { drizzle } from 'drizzle-orm/pg-proxy';
import axios from "axios";

const db = drizzle(async (sql, params, method) => {
  try {
    const rows = await axios.post('http://localhost:3000/query', { sql, params, method });

    return { rows: rows.data };
  } catch (e: any) {
    console.error('Error from pg proxy server: ', e.response.data)
    return { rows: [] };
  }
});
```
```ts
// Example of server implementation
import { Client } from 'pg';
import express from 'express';

const app = express();

app.use(express.json());
const port = 3000;

const client = new Client('postgres://postgres:postgres@localhost:5432/postgres');

app.post('/query', async (req, res) => {
  const { sql, params, method } = req.body;

  // prevent multiple queries
  const sqlBody = sql.replace(/;/g, '');

  try {
    const result = await client.query({
      text: sqlBody,
      values: params,
      rowMode: method === 'all' ? 'array': undefined,
    });
    res.send(result.rows);
  } catch (e: any) {
    res.status(500).json({ error: e });
  }

  res.status(500).json({ error: 'Unknown method value' });
});

app.listen(port, () => {
  console.log(`Example app listening on port ${port}`);
});
```
</Section>


Source: https://orm.drizzle.team/docs/pg/connect-effect-postgres

import Npm from "@mdx/Npm.astro";
import Callout from '@mdx/Callout.astro';
import AnchorCards from '@mdx/AnchorCards.astro';
import Steps from '@mdx/Steps.astro';
import WhatsNextPostgres from "@mdx/WhatsNextPostgres.astro";
import Prerequisites from "@mdx/Prerequisites.astro";
import CodeTabs from "@mdx/CodeTabs.astro";

# Drizzle \<\> Effect Postgres

<Prerequisites>
- Database [connection basics](/docs/connect-overview) with Drizzle
- Effect - [website](https://effect.website/docs)
- **@effect/sql-pg** - A PostgreSQL toolkit for Effect - [read here](https://effect-ts.github.io/effect/docs/sql-pg)
</Prerequisites>

Drizzle has native support for Effect PostgreSQL connections with the `@effect/sql-pg` driver.

#### Step 1 - Install packages
<Npm>
 drizzle-orm@rc effect @effect/sql-pg pg
 -D drizzle-kit@rc @types/pg
</Npm>

#### Step 2 - Initialize the driver and make a query

Drizzle provides an Effect-native API that integrates with Effect's service pattern. Use `PgDrizzle.makeWithDefaults()` 
to quickly create a Drizzle database instance with sensible defaults (no logging, no caching).

```typescript copy
import 'dotenv/config';
import * as PgDrizzle from 'drizzle-orm/effect-postgres';
import { PgClient } from '@effect/sql-pg';
import * as Effect from 'effect/Effect';
import * as Redacted from 'effect/Redacted';
import { sql } from 'drizzle-orm';
import { types } from 'pg';

// Configure the PgClient layer with type parsers
const PgClientLive = PgClient.layer({
  url: Redacted.make(process.env.DATABASE_URL!),
  types: {
    getTypeParser: (typeId, format) => {
      // Return raw values for date/time types to let Drizzle handle parsing
      if ([1184, 1114, 1082, 1186, 1231, 1115, 1185, 1187, 1182].includes(typeId)) {
        return (val: any) => val;
      }
      return types.getTypeParser(typeId, format);
    },
  },
});

const program = Effect.gen(function*() {
  // Create the database with default services (no logging, no caching)
  const db = yield* PgDrizzle.makeWithDefaults();

  // Execute queries
  const result = yield* db.execute<{ id: number }>(sql`SELECT 1 as id`);
  console.log(result);
});

// Run the program with the PgClient layer
Effect.runPromise(program.pipe(Effect.provide(PgClientLive)));
```

#### Step 3 - Create a DB Layer for dependency injection

For larger applications, create a reusable DB layer that can be composed with other services. This follows Effect's 
recommended pattern for dependency injection:

```typescript copy
import * as PgDrizzle from 'drizzle-orm/effect-postgres';
import { PgClient } from '@effect/sql-pg';
import * as Context from 'effect/Context';
import * as Effect from 'effect/Effect';
import * as Layer from 'effect/Layer';
import * as Redacted from 'effect/Redacted';
import { types } from 'pg';
import * as relations from './schema/relations';

// Configure the PgClient layer
const PgClientLive = PgClient.layer({
  url: Redacted.make(process.env.DATABASE_URL!),
  types: {
    getTypeParser: (typeId, format) => {
      if ([1184, 1114, 1082, 1186, 1231, 1115, 1185, 1187, 1182].includes(typeId)) {
        return (val: any) => val;
      }
      return types.getTypeParser(typeId, format);
    },
  },
});

// Create the DB effect with default services
const dbEffect = PgDrizzle.make({ relations }).pipe(
  Effect.provide(PgDrizzle.DefaultServices)
);

// Define a DB service tag for dependency injection
class DB extends Context.Tag('DB')<DB, Effect.Effect.Success<typeof dbEffect>>() {}

// Create a layer that provides the DB service
const DBLive = Layer.effect(
  DB,
  Effect.gen(function*() {
    return yield* dbEffect;
  }),
);

// Compose all layers together
const AppLive = Layer.provideMerge(DBLive, PgClientLive);

// Use the DB service in your application
const program = Effect.gen(function*() {
  const db = yield* DB;
  const users = yield* db.select().from(usersTable);
  return users;
});

// Run with all dependencies provided
Effect.runPromise(program.pipe(Effect.provide(AppLive)));
```

#### Advanced: Custom logger and cache configuration

For more control over logging and caching, use `PgDrizzle.make()` directly and provide your own service implementations.

##### Logger configuration

By default, `makeWithDefaults()` uses a no-op logger (no logging). You can enable logging by providing 
a different `EffectLogger` implementation:

```typescript copy
import * as PgDrizzle from 'drizzle-orm/effect-postgres';
import { EffectLogger } from 'drizzle-orm/effect-postgres';
import * as Effect from 'effect/Effect';

const program = Effect.gen(function*() {
  const db = yield* PgDrizzle.make({ /* schema, relations, casing */ }).pipe(
    // Enable Effect-based logging (uses Effect.log with annotations)
    Effect.provide(EffectLogger.layer),
    // Provide remaining default services (cache)
    Effect.provide(PgDrizzle.DefaultServices),
  );

  const users = yield* db.select().from(usersTable);
  return users;
});
```

**Available logger options:**
- `EffectLogger.Default` - No-op logger (no logging occurs) - this is the default
- `EffectLogger.layer` - Logs queries using Effect's `Effect.log()` with annotations for query SQL and parameters. Integrates with Effect's logging infrastructure.
- `EffectLogger.fromDrizzle(logger)` - Wraps a Drizzle `Logger` instance for use with Effect
- `EffectLogger.layerFromDrizzle(logger)` - Creates an Effect Layer from a Drizzle logger

<Callout type='info'>
When using `EffectLogger.layer`, queries are logged via Effect's logging system. You can configure the output 
format by providing a different Effect logger layer (e.g., `Logger.pretty` for development, `Logger.json` for production).
</Callout>

**Using a Drizzle logger:**

```typescript copy
import * as PgDrizzle from 'drizzle-orm/effect-postgres';
import { EffectLogger } from 'drizzle-orm/effect-postgres';
import * as Effect from 'effect/Effect';
import { DefaultLogger } from 'drizzle-orm';

const program = Effect.gen(function*() {
  const db = yield* PgDrizzle.make({ /* schema, relations, casing */ }).pipe(
    // Use a Drizzle logger wrapped for Effect
    Effect.provide(EffectLogger.layerFromDrizzle(new DefaultLogger())),
    // Provide remaining default services (cache)
    Effect.provide(PgDrizzle.DefaultServices),
  );

  const users = yield* db.select().from(usersTable);
  return users;
});
```

##### Cache configuration

Similarly, you can provide a custom cache implementation:

```typescript copy
import * as PgDrizzle from 'drizzle-orm/effect-postgres';
import { EffectLogger } from 'drizzle-orm/effect-postgres';
import { EffectCache } from 'drizzle-orm/cache/core/cache-effect';
import * as Effect from 'effect/Effect';
import { MyCustomCache } from './cache';

const program = Effect.gen(function*() {
  const db = yield* PgDrizzle.make({ /* schema, relations, casing */ }).pipe(
    // Provide a custom cache wrapped for Effect
    Effect.provide(EffectCache.layerFromDrizzle(new MyCustomCache())),
    // Provide remaining default services (logger)
    Effect.provide(PgDrizzle.DefaultServices),
  );

  const users = yield* db.select().from(usersTable);
  return users;
});
```

**Available cache options:**
- `EffectCache.Default` - No-op cache (no caching occurs) - this is the default
- `EffectCache.fromDrizzle(cache)` - Wraps a Drizzle `Cache` instance for use with Effect
- `EffectCache.layerFromDrizzle(cache)` - Creates an Effect Layer from a Drizzle cache (useful for composing with other layers)

#### What's next?

<WhatsNextPostgres/>


Source: https://orm.drizzle.team/docs/pg/connect-neon

import Tab from '@mdx/Tab.astro';
import Tabs from '@mdx/Tabs.astro';
import Npm from "@mdx/Npm.astro";
import Callout from '@mdx/Callout.astro';
import Steps from '@mdx/Steps.astro';
import AnchorCards from '@mdx/AnchorCards.astro';
import Prerequisites from "@mdx/Prerequisites.astro";
import CodeTabs from "@mdx/CodeTabs.astro";
import Section from "@mdx/Section.astro";
import WhatsNextPostgres from "@mdx/WhatsNextPostgres.astro";

# Drizzle \<\> Neon Postgres
<Prerequisites>
- Database [connection basics](/docs/connect-overview) with Drizzle
- Neon serverless database - [website](https://neon.tech)
- Neon serverless driver - [docs](https://neon.tech/docs/serverless/serverless-driver) & [GitHub](https://github.com/neondatabase/serverless)
- Drizzle PostgreSQL drivers - [docs](/docs/get-started-postgresql)
</Prerequisites>

Drizzle has native support for Neon connections with the `neon-http` and `neon-websockets` drivers. These use the **neon-serverless** driver under the hood.  
  
With the `neon-http` and `neon-websockets` drivers, you can access a Neon database from serverless environments over HTTP or WebSockets instead of TCP.  
Querying over HTTP is faster for single, non-interactive transactions.  
  
If you need session or interactive transaction support, or a fully compatible drop-in replacement for the `pg` driver, you can use the WebSocket-based `neon-serverless` driver.  
You can connect to a Neon database directly using [Postgres](/docs/get-started/postgresql-new)
  
For an example of using Drizzle ORM with the Neon Serverless driver in a Cloudflare Worker, **[see here.](http://driz.link/neon-cf-ex)**  
To use Neon from a serverful environment, you can use the node-postgres or Postgres.js drivers, as described in Neon's **[official Node.js docs](https://neon.tech/docs/guides/node)**

#### Step 1 - Install packages
<CodeTabs items={["@neondatabase/serverless", "node-postgres", "postgres.js"]}>
<Npm>
 drizzle-orm@rc @neondatabase/serverless
 -D drizzle-kit@rc
</Npm>

<Npm>
 drizzle-orm@rc pg
 -D drizzle-kit@rc
</Npm>

<Npm>
 drizzle-orm@rc postres
 -D drizzle-kit@rc
</Npm>

</CodeTabs>

#### Step 2 - Initialize the driver and make a query
<CodeTabs items={["Neon HTTP", "Neon Websockets", "node-postgres", "postgres.js"]}>
```typescript
// Make sure to install the '@neondatabase/serverless' package 
import { drizzle } from 'drizzle-orm/neon-http';

const db = drizzle(process.env.DATABASE_URL);

const result = await db.execute('select 1');
```
<Section> 
```typescript 
// Make sure to install the '@neondatabase/serverless' package 
import { drizzle } from 'drizzle-orm/neon-serverless';

const db = drizzle(process.env.DATABASE_URL);

const result = await db.execute('select 1');
```
```typescript
// For Node.js - make sure to install the 'ws' and 'bufferutil' packages
import { drizzle } from 'drizzle-orm/neon-serverless';
import ws from 'ws';

const db = drizzle({
  connection: process.env.DATABASE_URL,
  ws: ws,
});

const result = await db.execute('select 1');
```
<Callout type="warning" emoji="⚙️"> 
Additional configuration is required to use WebSockets in environments where the `WebSocket` global is not defined, such as Node.js. 
Add the `ws` and `bufferutil` packages to your project's dependencies, and set `ws` in the Drizzle config. 
</Callout>
</Section> 
```typescript 
// Make sure to install the 'pg' package 
import { drizzle } from 'drizzle-orm/node-postgres';

const db = drizzle(process.env.DATABASE_URL);
 
const result = await db.execute('select 1');
```
```typescript
// Make sure to install the 'postgres' package
import { drizzle } from 'drizzle-orm/postgres-js';

const db = drizzle(process.env.DATABASE_URL);

const result = await db.execute('select 1');
```
</CodeTabs>

If you need to provide your existing drivers:

<CodeTabs items={["Neon HTTP", "Neon Websockets", "node-postgres", "postgres.js"]}>
```typescript
// Make sure to install the '@neondatabase/serverless' package 
import { neon } from '@neondatabase/serverless';
import { drizzle } from 'drizzle-orm/neon-http';

const sql = neon(process.env.DATABASE_URL!);
const db = drizzle({ client: sql });

const result = await db.execute('select 1');
```
<Section> 
```typescript
// Make sure to install the '@neondatabase/serverless' package 
import { Pool } from '@neondatabase/serverless';
import { drizzle } from 'drizzle-orm/neon-serverless';

const pool = new Pool({ connectionString: process.env.DATABASE_URL });
const db = drizzle({ client: pool })

const result = await db.execute('select 1');
```
```typescript
// For Node.js - make sure to install the 'ws' and 'bufferutil' packages
import { Pool, neonConfig } from '@neondatabase/serverless';
import { drizzle } from 'drizzle-orm/neon-serverless';

neonConfig.webSocketConstructor = ws;

const pool = new Pool({ connectionString: process.env.DATABASE_URL });
const db = drizzle({ client: pool })

const result = await db.execute('select 1');
```
<Callout type="warning" emoji="⚙️"> 
Additional configuration is required to use WebSockets in environments where the `WebSocket` global is not defined, such as Node.js. 
Add the `ws` and `bufferutil` packages to your project's dependencies, and set `ws` in the Drizzle config. 
</Callout>
</Section> 
```typescript 
// Make sure to install the 'pg' package 
import { drizzle } from "drizzle-orm/node-postgres";
import { Pool } from "pg";

const pool = new Pool({
  connectionString: process.env.DATABASE_URL,
});
const db = drizzle({ client: pool });
 
const result = await db.execute('select 1');
```
```typescript
// Make sure to install the 'postgres' package
import { drizzle } from 'drizzle-orm/postgres-js';
import postgres from 'postgres';

const queryClient = postgres(process.env.DATABASE_URL);
const db = drizzle({ client: queryClient });

const result = await db.execute('select 1');
```
</CodeTabs>

#### What's next?

<WhatsNextPostgres/>


Source: https://orm.drizzle.team/docs/pg/connect-netlify-db

import Tab from '@mdx/Tab.astro';
import Tabs from '@mdx/Tabs.astro';
import Npm from "@mdx/Npm.astro";
import Callout from '@mdx/Callout.astro';
import Steps from '@mdx/Steps.astro';
import AnchorCards from '@mdx/AnchorCards.astro';
import Prerequisites from "@mdx/Prerequisites.astro";
import CodeTabs from "@mdx/CodeTabs.astro";
import Section from "@mdx/Section.astro";
import WhatsNextPostgres from "@mdx/WhatsNextPostgres.astro";

# Drizzle \<\> Netlify Database
<Prerequisites>
- Database [connection basics](/docs/connect-overview) with Drizzle
- Netlify Database - [website](https://docs.netlify.com/build/data-and-storage/netlify-database/)
</Prerequisites>

<Callout type="warning">
The Netlify Database driver is developed and maintained by the Netlify team.
</Callout>

Drizzle has native support for Netlify Database connections, that intelligently selects the optimal underlying Postgres driver based on the runtime environment.

Netlify Database is a managed Postgres database. On Netlify's platform, the same application code runs in two very different contexts:

- Serverless functions: no persistent connections, best served by HTTP-based queries
- Server mode: persistent connections via node-postgres

This adapter abstracts that decision away so consumers can write `drizzle()` once and get the right driver automatically.
  
#### Step 1 - Install packages
<Npm>
 drizzle-orm@rc @netlify/database
 -D drizzle-kit@rc
</Npm>

#### Step 2 - Initialize the driver and make a query
<CodeTabs items={["Zero config", "Connection string", "Explicit client"]}>
```typescript
import { drizzle } from 'drizzle-orm/netlify-db';

// Connection string is set automatically by the platform
const db = drizzle();

const result = await db.execute('select 1');
```
<Section> 
```typescript 
import { drizzle } from 'drizzle-orm/netlify-db';

const db = drizzle(process.env.DATABASE_URL);

const result = await db.execute('select 1');
```
</Section> 
```typescript
import { drizzle } from 'drizzle-orm/netlify-db';

// Explicit client — consumer controls the driver
const db = drizzle({ client: netlifyDbClient });

const result = await db.execute('select 1');
```
</CodeTabs>

#### What's next?

<WhatsNextPostgres/>


Source: https://orm.drizzle.team/docs/pg/connect-nile

import Tab from '@mdx/Tab.astro';
import Tabs from '@mdx/Tabs.astro';
import Npm from "@mdx/Npm.astro";
import Callout from '@mdx/Callout.astro';
import Steps from '@mdx/Steps.astro';
import AnchorCards from '@mdx/AnchorCards.astro';
import Prerequisites from "@mdx/Prerequisites.astro";
import WhatsNextPostgres from "@mdx/WhatsNextPostgres.astro";

# Drizzle \<\> Nile

<Prerequisites>
- Database [connection basics](/docs/connect-overview) with Drizzle
- Nile Database - [website](https://thenile.dev)
- Drizzle PostgreSQL drivers - [docs](/docs/get-started-postgresql)
</Prerequisites>

According to the **[official website](https://thenile.dev)**, Nile is PostgreSQL re-engineered for multi-tenant apps.

Checkout official **[Nile + Drizzle Quickstart](https://www.thenile.dev/docs/getting-started/languages/drizzle)** and **[Migration](https://www.thenile.dev/docs/getting-started/schema_migrations/drizzle)** docs.

You can use Nile with any of Drizzle's Postgres drivers, we'll be showing the use of `node-postgres` below.

#### Step 1 - Install packages

<Npm>
 drizzle-orm@rc pg
 -D drizzle-kit@rc
</Npm>

#### Step 2 - Initialize the driver and make a query

```typescript copy filename="index.ts"
// Make sure to install the 'pg' package
import { drizzle } from 'drizzle-orm/node-postgres'

const db = drizzle(process.env.NILEDB_URL);

const response = await db.select().from(...);
```

If you need to provide your existing driver:

```typescript copy filename="index.ts"
// Make sure to install the 'pg' package
import { drizzle } from "drizzle-orm/node-postgres";
import { Pool } from "pg";

const pool = new Pool({
  connectionString: process.env.DATABASE_URL,
});

const db = drizzle({ client: pool });

const response = await db.select().from(...);
```

#### Connecting to a virtual tenant database

Nile provides virtual tenant databases, when you set the tenant context, Nile will direct your queries to the virtual database for this particular tenant and all queries will apply to that tenant (i.e. `select * from table` will result records only for this tenant). 

In order to set the tenant context, we wrap each query in a transaction that sets the appropriate tenant context before running the transaction.

The tenant ID can simply be passed into the wrapper as an argument:

```typescript copy filename="index.ts"
import { drizzle } from 'drizzle-orm/node-postgres';
import { todosTable, tenants } from "./db/schema";
import { sql } from 'drizzle-orm';
import 'dotenv/config';

const db = drizzle(process.env.NILEDB_URL);

function tenantDB<T>(tenantId: string, cb: (tx: any) => T | Promise<T>): Promise<T> {
  return db.transaction(async (tx) => {
    if (tenantId) {
      await tx.execute(sql`set local nile.tenant_id = '${sql.raw(tenantId)}'`);
    }

    return cb(tx);
  }) as Promise<T>;
}

// In a webapp, you'll likely get it from the request path parameters or headers
const tenantId = '01943e56-16df-754f-a7b6-6234c368b400'

const response = await tenantDB(tenantId, async (tx) => {
    // No need for a "where" clause here
    return await tx.select().from(todosTable);
});

console.log(response);
```

If you are using a web framwork that supports it, you can set up [AsyncLocalStorage](https://nodejs.org/api/async_context.html) and use middleware to populate it with the tenant ID. In this case, your Drizzle client setup will be:

```typescript copy filename="db/index.ts
import { drizzle } from 'drizzle-orm/node-postgres';
import dotenv from "dotenv/config";
import { sql } from "drizzle-orm";
import { AsyncLocalStorage } from "async_hooks";

export const db = drizzle(process.env.NILEDB_URL);
export const tenantContext = new AsyncLocalStorage<string | undefined>();

export function tenantDB<T>(cb: (tx: any) => T | Promise<T>): Promise<T> {
  return db.transaction(async (tx) => {
    const tenantId = tenantContext.getStore();
    console.log("executing query with tenant: " + tenantId);
    // if there's a tenant ID, set it in the transaction context
    if (tenantId) {
      await tx.execute(sql`set local nile.tenant_id = '${sql.raw(tenantId)}'`);
    }

    return cb(tx);
  }) as Promise<T>;
}
```

And then, configure a middleware to populate the the AsyncLocalStorage and use `tenantDB` method when handling requests:

```typescript copy filename="app.ts"
// Middleware to set tenant context
app.use("/api/tenants/:tenantId/*", async (c, next) => {
  const tenantId = c.req.param("tenantId");
  console.log("setting context to tenant: " + tenantId);
  return tenantContext.run(tenantId, () => next());
});

// Route handler
app.get("/api/tenants/:tenantId/todos", async (c) => {
    const todos = await tenantDB(c, async (tx) => {
      return await tx
        .select({
          id: todoSchema.id,
          tenant_id: todoSchema.tenantId,
          title: todoSchema.title,
          estimate: todoSchema.estimate,
        })
        .from(todoSchema);
    });
    return c.json(todos);
});
```


#### What's next?

<WhatsNextPostgres/>



Source: https://orm.drizzle.team/docs/pg/connect-overview

# Database connection with Drizzle

Use these PostgreSQL drivers and providers with Drizzle ORM.

## PostgreSQL connection docs

- [PostgreSQL](/docs/get-started-postgresql)
- [PlanetScale Postgres](/docs/connect-planetscale-postgres)
- [Neon](/docs/connect-neon)
- [Vercel Postgres](/docs/connect-vercel-postgres)
- [Prisma Postgres](/docs/connect-prisma-postgres)
- [Supabase](/docs/connect-supabase)
- [Xata](/docs/connect-xata)
- [PGLite](/docs/connect-pglite)
- [Nile](/docs/connect-nile)
- [Bun SQL](/docs/connect-bun-sql)
- [Effect Postgres](/docs/connect-effect-postgres)
- [Netlify Database](/docs/connect-netlify-db)
- [Appwrite Postgres](/docs/connect-appwrite-postgres)
- [AWS Data API Postgres](/docs/connect-aws-data-api-pg)
- [Drizzle HTTP proxy](/docs/connect-drizzle-proxy)


Source: https://orm.drizzle.team/docs/pg/connect-pglite

import Tab from '@mdx/Tab.astro';
import Tabs from '@mdx/Tabs.astro';
import Npm from "@mdx/Npm.astro";
import Callout from '@mdx/Callout.astro';
import Steps from '@mdx/Steps.astro';
import AnchorCards from '@mdx/AnchorCards.astro';
import Prerequisites from "@mdx/Prerequisites.astro";
import CodeTabs from "@mdx/CodeTabs.astro";
import WhatsNextPostgres from "@mdx/WhatsNextPostgres.astro";

# Drizzle \<\> PGlite

<Prerequisites>
- Database [connection basics](/docs/connect-overview) with Drizzle
- ElectricSQL - [website](https://electric-sql.com/)
- PgLite driver - [docs](https://pglite.dev/) & [GitHub](https://github.com/electric-sql/pglite)
</Prerequisites>

According to the **[official repo](https://github.com/electric-sql/pglite)**, PGlite is a WASM Postgres build packaged into a TypeScript client library that enables you to run Postgres in the browser, Node.js and Bun, with no need to install any other dependencies. It is only 2.6mb gzipped.

It can be used as an ephemeral in-memory database, or with persistence either to the file system (Node/Bun) or indexedDB (Browser).

Unlike previous "Postgres in the browser" projects, PGlite does not use a Linux virtual machine - it is simply Postgres in WASM.

#### Step 1 - Install packages

<Npm>
 drizzle-orm@rc @electric-sql/pglite
 -D drizzle-kit@rc
</Npm>

#### Step 2 - Initialize the driver and make a query
<CodeTabs items={["In-Memory", "In directory", "With extra config options"]}>
```typescript copy"
import { drizzle } from 'drizzle-orm/pglite';

const db = drizzle();

await db.select().from(...);
```
```typescript copy"
import { drizzle } from 'drizzle-orm/pglite';

const db = drizzle('path-to-dir');

await db.select().from(...);
```
```typescript copy"
import { drizzle } from 'drizzle-orm/pglite';

// connection is a native PGLite configuration
const db = drizzle({ connection: { dataDir: 'path-to-dir' }});

await db.select().from(...);
```
</CodeTabs>

If you need to provide your existing driver:

```typescript copy"
import { PGlite } from '@electric-sql/pglite';
import { drizzle } from 'drizzle-orm/pglite';

// In-memory Postgres
const client = new PGlite();
const db = drizzle({ client });

await db.select().from(users);
```

#### What's next?

<WhatsNextPostgres/>


Source: https://orm.drizzle.team/docs/pg/connect-planetscale-postgres

import Npm from "@mdx/Npm.astro";
import Callout from "@mdx/Callout.astro";
import CodeTabs from "@mdx/CodeTabs.astro";
import Section from "@mdx/Section.astro";
import Prerequisites from "@mdx/Prerequisites.astro";
import WhatsNextPostgres from "@mdx/WhatsNextPostgres.astro";

# Drizzle \<\> PlanetScale Postgres

<Prerequisites>

- Database [connection basics](/docs/connect-overview) with Drizzle
- PlanetScale Postgres database - [docs](https://planetscale.com/docs/postgres)
- Drizzle PostgreSQL drivers - [docs](/docs/get-started-postgresql)

</Prerequisites>

PlanetScale offers both MySQL (Vitess) and PostgreSQL databases. This page covers connecting to PlanetScale Postgres.

For PlanetScale MySQL, see the [PlanetScale MySQL connection guide](/docs/mysql/connect-planetscale).

With Drizzle ORM you can connect to PlanetScale Postgres using:

- The standard `node-postgres` driver
- The `@neondatabase/serverless` driver for serverless environments

For detailed instructions on creating a PlanetScale Postgres database and obtaining credentials, see the [PlanetScale Postgres documentation](https://planetscale.com/docs/postgres/tutorials/planetscale-postgres-drizzle).

## node-postgres

#### Step 1 - Install packages

<Npm>
 drizzle-orm@rc pg
 -D drizzle-kit@rc @types/pg
</Npm>

#### Step 2 - Initialize the driver and make a query

<CodeTabs items={["Connection URL", "With config", "With existing client"]}>
```typescript copy
import { drizzle } from 'drizzle-orm/node-postgres';

const db = drizzle(process.env.DATABASE_URL);

const result = await db.execute('select 1');

````
```typescript copy
import { drizzle } from 'drizzle-orm/node-postgres';

const db = drizzle({
  connection: {
    connectionString: process.env.DATABASE_URL,
    ssl: true
  }
});

const result = await db.execute('select 1');
````

```typescript copy
import { drizzle } from "drizzle-orm/node-postgres";
import { Pool } from "pg";

const pool = new Pool({
  connectionString: process.env.DATABASE_URL,
});
const db = drizzle({ client: pool });

const result = await db.execute("select 1");
```

</CodeTabs>

## Neon serverless driver

PlanetScale Postgres also supports connections via the [Neon serverless driver](https://planetscale.com/docs/postgres/connecting/neon-serverless-driver). This is a good option for serverless environments like Vercel Functions, Cloudflare Workers, or AWS Lambda.

The driver supports two modes:

- **HTTP mode** — Faster for single queries and non-interactive transactions
- **WebSocket mode** — Required for interactive transactions or session-based features

#### Step 1 - Install packages

<Npm>
 drizzle-orm@rc @neondatabase/serverless
 -D drizzle-kit@rc
</Npm>

#### Step 2 - Initialize the driver and make a query

<CodeTabs items={["Neon HTTP", "Neon WebSockets"]}>
```typescript copy
import { neon, neonConfig } from '@neondatabase/serverless';
import { drizzle } from 'drizzle-orm/neon-http';

// Required for PlanetScale Postgres connections
neonConfig.fetchEndpoint = (host) => `https://${host}/sql`;

const sql = neon(process.env.DATABASE_URL!);
const db = drizzle({ client: sql });

const result = await db.execute('select 1');

````
<Section>
```typescript copy
import { Pool, neonConfig } from '@neondatabase/serverless';
import { drizzle } from 'drizzle-orm/neon-serverless';

// Required for PlanetScale Postgres connections
neonConfig.pipelineConnect = false;
neonConfig.wsProxy = (host, port) => `${host}/v2?address=${host}:${port}`;

const pool = new Pool({ connectionString: process.env.DATABASE_URL });
const db = drizzle({ client: pool });

const result = await db.execute('select 1');
````

```typescript copy
// For Node.js environments - install 'ws' package
import ws from "ws";
import { Pool, neonConfig } from "@neondatabase/serverless";
import { drizzle } from "drizzle-orm/neon-serverless";

neonConfig.webSocketConstructor = ws;
// Required for PlanetScale Postgres connections
neonConfig.pipelineConnect = false;
neonConfig.wsProxy = (host, port) => `${host}/v2?address=${host}:${port}`;

const pool = new Pool({ connectionString: process.env.DATABASE_URL });
const db = drizzle({ client: pool });

const result = await db.execute("select 1");
```

</Section>
</CodeTabs>

<Callout title="Connection URL format">
  {`postgresql://{username}:{password}@{host}:{port}/postgres?sslmode=verify-full`}
</Callout>

<Callout title="Connection ports" type="info">
  PlanetScale Postgres supports two connection ports:

`5432`: Direct connection to PostgreSQL. Total connections are limited by your cluster's `max_connections` setting.

`6432`: Connection via PgBouncer for connection pooling. Recommended when you have many simultaneous connections.

  </Callout>

#### What's next?

<WhatsNextPostgres />


Source: https://orm.drizzle.team/docs/pg/connect-prisma-postgres

import Tab from '@mdx/Tab.astro';
import Tabs from '@mdx/Tabs.astro';
import Npm from "@mdx/Npm.astro";
import Callout from '@mdx/Callout.astro';
import Steps from '@mdx/Steps.astro';
import AnchorCards from '@mdx/AnchorCards.astro';
import Prerequisites from "@mdx/Prerequisites.astro";
import CodeTabs from "@mdx/CodeTabs.astro";
import Section from "@mdx/Section.astro";
import WhatsNextPostgres from "@mdx/WhatsNextPostgres.astro";

# Drizzle \<\> Prisma Postgres
<Prerequisites>
- Database [connection basics](/docs/connect-overview) with Drizzle
- Prisma Postgres serverless database - [website](https://prisma.io/postgres)
- Prisma Postgres direct connections - [docs](https://www.prisma.io/docs/postgres/database/direct-connections) 
- Drizzle PostgreSQL drivers - [docs](/docs/get-started-postgresql)
</Prerequisites>

Prisma Postgres is a serverless database built on [unikernels](https://www.prisma.io/blog/announcing-prisma-postgres-early-access). It has a large free tier, [operation-based pricing](https://www.prisma.io/blog/operations-based-billing) and no cold starts.
  
You can connect to it using either the [`node-postgres`](https://node-postgres.com/) or [`postgres.js`](https://github.com/porsager/postgres) drivers for PostgreSQL.

<Callout type="info">
Prisma Postgres also has a [serverless driver](https://www.prisma.io/docs/postgres/database/serverless-driver) that will be supported with Drizzle ORM in the future.
</Callout>

#### Step 1 - Install packages
<CodeTabs items={["node-postgres (pg)", "postgres.js"]}>
<Npm>
 drizzle-orm@rc pg
 -D drizzle-kit@rc
</Npm>

<Npm>
 drizzle-orm@rc postres
 -D drizzle-kit@rc
</Npm>

</CodeTabs>


#### Step 2 - Initialize the driver and make a query
<CodeTabs items={["node-postgres (pg)", "postgres.js"]}>
```typescript 
// Make sure to install the 'pg' package 
import { drizzle } from "drizzle-orm/node-postgres";
import { Pool } from "pg";

const pool = new Pool({
  connectionString: process.env.DATABASE_URL,
});
const db = drizzle({ client: pool });
 
const result = await db.execute('select 1');
```
```typescript
// Make sure to install the 'postgres' package
import { drizzle } from 'drizzle-orm/postgres-js';
import postgres from 'postgres';

const queryClient = postgres(process.env.DATABASE_URL);
const db = drizzle({ client: queryClient });

const result = await db.execute('select 1');
```
</CodeTabs>

#### What's next?

<WhatsNextPostgres/>


Source: https://orm.drizzle.team/docs/pg/connect-supabase

import Tab from '@mdx/Tab.astro';
import Tabs from '@mdx/Tabs.astro';
import Npm from "@mdx/Npm.astro";
import Callout from '@mdx/Callout.astro';
import Steps from '@mdx/Steps.astro';
import AnchorCards from '@mdx/AnchorCards.astro';
import Prerequisites from "@mdx/Prerequisites.astro";
import WhatsNextPostgres from "@mdx/WhatsNextPostgres.astro";

# Drizzle \<\> Supabase

<Prerequisites>
- Database [connection basics](/docs/connect-overview) with Drizzle
- Drizzle PostgreSQL drivers - [docs](/docs/get-started-postgresql)
</Prerequisites>

According to the **[official website](https://supabase.com/docs)**, Supabase is an open source Firebase alternative for building secure and performant Postgres backends with minimal configuration.

Checkout official **[Supabase + Drizzle](https://supabase.com/docs/guides/database/drizzle)** docs.

#### Step 1 - Install packages

<Npm>
 drizzle-orm@rc postgres
 -D drizzle-kit@rc
</Npm>

#### Step 2 - Initialize the driver and make a query

```typescript copy filename="index.ts"
import { drizzle } from 'drizzle-orm/postgres-js'

const db = drizzle(process.env.DATABASE_URL);

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

If you need to provide your existing driver:
```typescript copy filename="index.ts"
import { drizzle } from 'drizzle-orm/postgres-js'
import postgres from 'postgres'

const client = postgres(process.env.DATABASE_URL)
const db = drizzle({ client });

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

If you decide to use connection pooling via Supabase (described [here](https://supabase.com/docs/guides/database/connecting-to-postgres#poolers)), and have "Transaction" pool mode enabled, then ensure to turn off prepare, as prepared statements are not supported. 

```typescript copy filename="index.ts"
import { drizzle } from 'drizzle-orm/postgres-js'
import postgres from 'postgres'

// Disable prefetch as it is not supported for "Transaction" pool mode 
const client = postgres(process.env.DATABASE_URL, { prepare: false })
const db = drizzle({ client });

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

Connect to your database using the Connection Pooler for **serverless environments**, and the Direct Connection for **long-running servers**.

#### What's next?

<WhatsNextPostgres/>


Source: https://orm.drizzle.team/docs/pg/connect-vercel-postgres

import Tab from '@mdx/Tab.astro';
import Tabs from '@mdx/Tabs.astro';
import Npm from "@mdx/Npm.astro";
import Callout from '@mdx/Callout.astro';
import Steps from '@mdx/Steps.astro';
import AnchorCards from '@mdx/AnchorCards.astro';
import Prerequisites from "@mdx/Prerequisites.astro";
import WhatsNextPostgres from "@mdx/WhatsNextPostgres.astro";

# Drizzle \<\> Vercel Postgres

<Prerequisites>
- Database [connection basics](/docs/connect-overview) with Drizzle
- Vercel Postgres database - [website](https://vercel.com/docs/storage/vercel-postgres)
- Vercel Postgres driver - [docs](https://vercel.com/docs/storage/vercel-postgres/sdk) & [GitHub](https://github.com/vercel/storage/tree/main/packages/postgres)
- Drizzle PostgreSQL drivers - [docs](/docs/get-started-postgresql)
</Prerequisites>

According to their **[official website](https://vercel.com/docs/storage/vercel-postgres)**,
Vercel Postgres is a serverless SQL database designed to integrate with Vercel Functions.

Drizzle ORM natively supports both **[@vercel/postgres](https://vercel.com/docs/storage/vercel-postgres)** serverless
driver with `drizzle-orm/vercel-postgres` package and **[`postgres`](#postgresjs)** or **[`pg`](#node-postgres)**
drivers to access Vercel Postgres through `postgesql://`

Check out the official **[Vercel Postgres + Drizzle](https://vercel.com/docs/storage/vercel-postgres/using-an-orm#drizzle)** docs.

#### Step 1 - Install packages

<Npm>
 drizzle-orm@rc @vercel/postgres
 -D drizzle-kit@rc
</Npm>

#### Step 2 - Prepare Vercel Postgres

Setup a project according to the **[official docs.](https://vercel.com/docs/storage/vercel-postgres/quickstart)** 

#### Step 3 - Initialize the driver and make a query

```typescript copy
import { drizzle } from 'drizzle-orm/vercel-postgres';

const db = drizzle();

const result = await db.execute('select 1');
```

If you need to provide your existing driver:

```typescript copy
import { sql } from '@vercel/postgres';
import { drizzle } from 'drizzle-orm/vercel-postgres';

const db = drizzle({ client: sql })

const result = await db.execute('select 1');
```

With **[@vercel/postgres](https://vercel.com/docs/storage/vercel-postgres)** severless package
you can access Vercel Postgres from either serverful or serverless environments with no TCP available,
like Cloudflare Workers, through websockets.  
  
If you're about to use Vercel Postgres from a _serverfull_ environment, you can do it
either with `@vercel/postgres` or directly access the DB through `postgesql://` with 
either **[`postgres`](#postgresjs)** or **[`pg`](#node-postgres)**.

#### What's next?

<WhatsNextPostgres/>


Source: https://orm.drizzle.team/docs/pg/connect-xata

import Tab from '@mdx/Tab.astro';
import Tabs from '@mdx/Tabs.astro';
import Npm from "@mdx/Npm.astro";
import Callout from '@mdx/Callout.astro';
import Steps from '@mdx/Steps.astro';
import AnchorCards from '@mdx/AnchorCards.astro';
import Prerequisites from "@mdx/Prerequisites.astro";
import WhatsNextPostgres from "@mdx/WhatsNextPostgres.astro";
import CodeTabs from "@mdx/CodeTabs.astro";

# Drizzle \<\> Xata

<Prerequisites>
- Database [connection basics](/docs/connect-overview) with Drizzle
- Drizzle PostgreSQL drivers - [docs](/docs/get-started-postgresql)
</Prerequisites>

**[Xata](https://xata.io)** is a PostgreSQL database platform designed to help developers operate and scale databases with enhanced productivity and performance. Xata provides features like instant copy-on-write database branches, zero-downtime schema changes, data anonymization, AI-powered performance monitoring, and BYOC. 

Checkout official **[Xata + Drizzle](https://xata.io/documentation/quickstarts/drizzle)** docs.

#### Step 1 - Install packages

<Npm>
 drizzle-orm@rc postgres
 -D drizzle-kit@rc
</Npm>

#### Step 2 - Initialize the driver and make a query

```typescript copy filename="index.ts"
import { drizzle } from 'drizzle-orm/postgres-js'

const db = drizzle(process.env.DATABASE_URL);

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

If you need to provide your existing driver:
```typescript copy filename="index.ts"
import { drizzle } from 'drizzle-orm/postgres-js'
import postgres from 'postgres'

const client = postgres(process.env.DATABASE_URL)
const db = drizzle({ client });

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

#### What's next?

<WhatsNextPostgres/>


Source: https://orm.drizzle.team/docs/pg/custom-types

import Callout from "@mdx/Callout.astro";

# Custom types

Custom types let you define your own column types with custom SQL data types and JS/DB value transforms

PostgreSQL exposes `customType` from `drizzle-orm/pg-core`.

## Examples
The best way to see how `customType` definition is working is to check how existing data types could be defined using `customType` function from Drizzle ORM.

#### Integer

```ts
import { customType, pgTable } from 'drizzle-orm/pg-core';

const customInteger = customType<{ data: number; }>(
  {
    dataType() {
      return 'integer';
    },
  },
);

export const users = pgTable("users", {
  id: customInteger(),
});
```

#### Text
```ts
import { customType, pgTable } from 'drizzle-orm/pg-core';

const customText = customType<{ data: string }>({
  dataType() {
    return 'text';
  },
});

export const users = pgTable('users', {
  name: customText(),
});
```

#### Timestamp
```ts
import { customType, pgTable } from 'drizzle-orm/pg-core';

const customTimestamp = customType<{
  data: Date;
  driverData: string;
  config: { withTimezone: boolean; precision?: number };
  configRequired: false;
}>({
  dataType(config) {
    const precision = typeof config?.precision !== 'undefined' ? ` (${config.precision})` : '';
    return `timestamp${precision}${config?.withTimezone ? ' with time zone' : ''}`;
  },
  fromDriver(value: string): Date {
    return new Date(value);
  },
  codec: (config) => {
    if (config?.withTimezone) return 'timestamp with time zone';

    return 'timestamp';
  },
});

export const users = pgTable('users', {
  createdAt: customTimestamp('created_at'),
});
```

Usage for all types will be same as defined functions in Drizzle ORM. For example:
```ts
const usersTable = pgTable('users', {
  id: customInteger().primaryKey(),
  name: customText().notNull(),
  createdAt: customTimestamp('created_at', { withTimezone: true }).notNull()
    .default(sql`now()`),
});
```

### Methods and Generic types
<br/>

| Type | Required | Description |
|---|---|---|
| `data` | Yes | The TypeScript type for the column after selecting/inserting. |
| `driverData` | No | The type the database driver accepts for this data type. |
| `driverOutput` | No | **Deprecated** — use codecs instead (bypasses JSON codecs if used). The type the driver returns, if different from `driverData`. |
| `jsonData` | No | **Deprecated** — use codecs instead (bypasses JSON codecs if used). The type returned when aggregated to JSON. |
| `config` | No | Config object type for `dataType` generation (e.g. `{ length: number }`). |
| `configRequired` | No | Whether the config argument is required. Default `false`. |
| `notNull` | No | Set to `true` if the custom type should be `notNull` by default. |
| `default` | No | Set to `true` if the custom type has a default value. |

<br/>

| Method | Required | Description |
|---|---|---|
| `dataType` | Yes | Defines the SQL type string. If database data type needs additional params you can use them from `config` param |
| `toDriver` | No | Transform inputs from desired to be used in code format to one suitable for driver |
| `fromDriver` | No | Transform data returned by driver to desired column's output format |
| `codec` | No | Which driver codec to use (see [Codecs](/docs/codecs) section). |
| `fromJson` | No | **Deprecated** — use `codec` instead. Transforms value from JSON context. |
| `forJsonSelect` | No | **Deprecated** — use `codec` instead. Modify selection of column inside JSON functions |

<br/>

## TS-doc for type definitions

You can check `ts-doc` for types, param definition and examples

<Callout collapsed="Expand details">
```ts
interface CustomTypeValues {
  /**
   * Required type for custom column, that will infer proper type model
   *
   * Examples:
   *
   * If you want your column to be `string` type after selecting/or on inserting - use `data: string`. Like `text`, `varchar`
   *
   * If you want your column to be `number` type after selecting/or on inserting - use `data: number`. Like `integer`
   */
  data: unknown;
  /**
   * Type helper, that represents what type database driver is accepting for specific database data type
   */
  driverData?: unknown;
  /**
   * @deprecated Use codecs instead
   *
   * Type helper, that represents what type database driver is returning for specific database data type
   *
   * Needed only in case driver's output and input for type differ
   *
   * Defaults to {@link driverData}
   */
  driverOutput?: unknown;
  /**
   * @deprecated Use codecs instead
   *
   * Type helper, that represents what type field returns after being aggregated to JSON
   */
  jsonData?: unknown;
  /**
   * What config type should be used for {@link CustomTypeParams} `dataType` generation
   */
  config?: Record<string, any>;
  /**
   * Whether the config argument should be required or not
   * @default false
   */
  configRequired?: boolean;
  /**
   * If your custom data type should be notNull by default you can use `notNull: true`
   *
   * @example
   * const customSerial = customType<{ data: number, notNull: true, default: true }>({
   * 	  dataType() {
   * 	    return 'serial';
   *    },
   * });
   */
  notNull?: boolean;
  /**
   * If your custom data type has default you can use `default: true`
   *
   * @example
   * const customSerial = customType<{ data: number, notNull: true, default: true }>({
   * 	  dataType() {
   * 	    return 'serial';
   *    },
   * });
   */
  default?: boolean;
}
interface CustomTypeParams<T extends CustomTypeValues> {
  /**
   * Database data type string representation, that is used for migrations
   * @example
   * ```
   * `jsonb`, `text`
   * ```
   *
   * If database data type needs additional params you can use them from `config` param
   * @example
   * ```
   * `varchar(256)`, `numeric(2,3)`
   * ```
   *
   * To make `config` be of specific type please use config generic in {@link CustomTypeValues}
   *
   * @example
   * Usage example
   * ```
   *   dataType() {
   *     return 'boolean';
   *   },
   * ```
   * Or
   * ```
   *   dataType(config) {
   * 	   return typeof config.length !== 'undefined' ? `varchar(${config.length})` : `varchar`;
   * 	 }
   * ```
   */
  dataType: (config: T['config'] | (Equal<T['configRequired'], true> extends true ? never : undefined)) => string;
  /**
   * Optional mapping function, that is used to transform inputs from desired to be used in code format to one suitable for driver
   * @example
   * For example, when using jsonb we need to map JS/TS object to string before writing to database
   * ```
   * toDriver(value: TData): string {
   * 	 return JSON.stringify(value);
   * }
   * ```
   */
  toDriver?: (value: T['data']) => T['driverData'] | SQL;
  /**
   * Optional mapping function, that is used for transforming data returned by driver to desired column's output format
   * @example
   * For example, when using timestamp we need to map string Date representation to JS Date
   * ```
   * fromDriver(value: string): Date {
   * 	return new Date(value);
   * }
   * ```
   *
   * It'll cause the returned data to change from:
   * ```
   * {
   * 	customField: "2025-04-07T03:25:16.635Z";
   * }
   * ```
   * to:
   * ```
   * {
   * 	customField: new Date("2025-04-07T03:25:16.635Z");
   * }
   * ```
   */
  fromDriver?: (value: 'driverOutput' extends keyof T ? T['driverOutput'] : T['driverData']) => T['data'];
  /**
   * @deprecated Use codecs instead; bypasses JSON codecs if used
   *
   * Optional mapping function, that is used for transforming data returned by transofmed to JSON in database data to desired format
   *
   * Used by [relational queries](https://orm.drizzle.team/docs/rqb)
   *
   * Defaults to {@link fromDriver} function
   * @example
   * For example, when querying bigint column via [RQB](https://orm.drizzle.team/docs/rqb) or JSON functions, the result field will be returned as it's string representation, as opposed to bigint from regular query
   * To handle that, we need a separate function to handle such field's mapping:
   * ```
   * fromJson(value: string): bigint {
   * 	return BigInt(value);
   * },
   * ```
   *
   * It'll cause the returned data to change from:
   * ```
   * {
   * 	customField: "5044565289845416380";
   * }
   * ```
   * to:
   * ```
   * {
   * 	customField: 5044565289845416380n;
   * }
   * ```
   */
  fromJson?: (value: T['jsonData']) => T['data'];
  /**
   * @deprecated Use codecs instead; bypasses JSON codecs if used
   *
   * Optional selection modifier function, that is used for modifying selection of column inside JSON functions
   *
   * Additional mapping that could be required for such scenarios can be handled using {@link fromJson} function
   *
   * Used by [relational queries](https://orm.drizzle.team/docs/rqb)
   *
   * Following types are being casted to text by default: `bytea`, `geometry`, `timestamp`, `numeric`, `bigint`
   * @example
   * For example, when using bigint we need to cast field to text to preserve data integrity
   * ```
   * forJsonSelect(identifier: SQL, sql: SQLGenerator, arrayDimensions?: number): SQL {
   * 	return sql`${identifier}::text`
   * },
   * ```
   *
   * This will change query from:
   * ```
   * SELECT
   * 	row_to_json("t".*)
   * 	FROM
   * 	(
   * 		SELECT
   * 		"table"."custom_bigint" AS "bigint"
   * 		FROM
   * 		"table"
   * 	) AS "t"
   * ```
   * to:
   * ```
   * SELECT
   * 	row_to_json("t".*)
   * 	FROM
   * 	(
   * 		SELECT
   * 		"table"."custom_bigint"::text AS "bigint"
   * 		FROM
   * 		"table"
   * 	) AS "t"
   * ```
   *
   * Returned by query object will change from:
   * ```
   * {
   * 	bigint: 5044565289845416000; // Partial data loss due to direct conversion to JSON format
   * }
   * ```
   * to:
   * ```
   * {
   * 	bigint: "5044565289845416380"; // Data is preserved due to conversion of field to text before JSON-ification
   * }
   * ```
   */
  forJsonSelect?: (identifier: SQL, sql: SQLGenerator, arrayDimensions?: number) => SQL;
  /**
   * Select which column type codec will be used for this column
   */
  codec?: PostgresColumnType | undefined | ((config: T['config'] | (Equal<T['configRequired'], true> extends true ? never : undefined)) => PostgresColumnType | undefined);
}
```
</Callout>

## Transform layers and execution order

Custom types have two transform layers: column-level (`toDriver`/`fromDriver`) and driver-level ([codecs](/docs/codecs)). Both run in a specific order. You can read more on how to use codecs with customTypes [here](/docs/codecs#how-codecs-work-in-customtype)

<br/>

- **Writes:** (Insert/Update) `toDriver` first → codec `normalizeParam` second
- **Reads:** (Select) codec `normalize` first → `fromDriver` second
- If no codec is set, only `toDriver`/`fromDriver` run
- If no `toDriver`/`fromDriver` is set, only codecs run (if defined)
- If neither is set, values pass through untouched

<br/>

Use both (`toDriver`/`fromDriver` and `codecs`) when you need driver-level normalization AND column-level transformation:

```ts
// DB stores as bigint, driver returns string, codec converts to BigInt,
// but you want a number in your app code
const myColumn = customType<{ data: number; driverData: string }>({
  dataType() { return 'bigint'; },
  codec: 'bigint',           // driver "123" → BigInt(123n)
  fromDriver(value) {        // BigInt(123n) → Number(123)
    return Number(value);
  },
});
```

But often you can simplify by choosing the right codec variant:

```ts
// Same result, no fromDriver needed
const myColumn = customType<{ data: number; driverData: string }>({
  dataType() { return 'bigint'; },
  codec: 'bigint:number',    // driver "123" → Number(123) directly
});
```

Source: https://orm.drizzle.team/docs/pg/data-querying

import Callout from '@mdx/Callout.astro';
import CodeTabs from "@mdx/CodeTabs.astro";
import Section from '@mdx/Section.astro';
import Flex from "@mdx/Flex.astro"
import LinksList from "@mdx/LinksList.astro"
import Prerequisites from "@mdx/Prerequisites.astro";

# Drizzle Queries + CRUD

<Prerequisites>
  - How to define your schema - [Schema Fundamentals](/docs/sql-schema-declaration)
  - How to connect to the database - [Connection Fundamentals](/docs/connect-overview)
</Prerequisites>

Drizzle gives you a few ways for querying your database and it's up to you to decide which one you'll need in your next project.
It can be either SQL-like syntax or Relational Syntax. Let's check them:

## Why SQL-like?
\
**If you know SQL, you know Drizzle.**

Other ORMs and data frameworks tend to deviate from or abstract away SQL, leading to a double learning curve: you need to learn both SQL and the framework's API.

Drizzle is the opposite.
We embrace SQL and built Drizzle to be SQL-like at its core, so you have little to no learning curve and full access to the power of SQL.

<Section>
```typescript copy
// Access your data
await db
  .select()
	.from(posts)
	.leftJoin(comments, eq(posts.id, comments.post_id))
	.where(eq(posts.id, 10))
```
```sql
SELECT *
FROM "posts"
LEFT JOIN "comments" ON "posts"."id" = "comments"."post_id"
WHERE "posts"."id" = 10
```
</Section>

With SQL-like syntax, you can replicate much of what you can do with pure SQL and know 
exactly what Drizzle will do and what query will be generated. You can perform a wide range of queries, 
including select, insert, update, delete, as well as using aliases, WITH clauses, subqueries, prepared statements, 
and more. Let's look at more examples

<CodeTabs items={['insert', 'update', 'delete']}>
<Section>
```ts
await db.insert(users).values({ email: 'user@gmail.com' })
```
```sql
INSERT INTO "users" ("email") VALUES ('user@gmail.com')
```
</Section>
<Section>
```ts
await db.update(users)
        .set({ email: 'user@gmail.com' })
        .where(eq(users.id, 1))
```
```sql
UPDATE "users"
SET "email" = 'user@gmail.com'
WHERE "users"."id" = 1
```
</Section>
<Section>
```ts
await db.delete(users).where(eq(users.id, 1))
```
```sql
DELETE FROM "users" WHERE "users"."id" = 1
```
</Section>
</CodeTabs>

## Why not SQL-like?

We're always striving for a perfectly balanced solution. While SQL-like queries cover 100% of your needs, 
there are certain common scenarios where data can be queried more efficiently.

We've built the Queries API so you can fetch relational, nested data from the database in the most convenient 
and performant way, without worrying about joins or data mapping.

**Drizzle always outputs exactly one SQL query**. Feel free to use it with serverless databases,
and never worry about performance or roundtrip costs!

<Section>
```ts
const result = await db.query.users.findMany({
	with: {
		posts: true
	},
});
```
{/* ```sql
SELECT * FROM users ...
``` */}
</Section>

## Advanced
With Drizzle, queries can be composed and partitioned in any way you want. You can compose filters 
independently from the main query, separate subqueries or conditional statements, and much more. 
Let's check a few advanced examples:

#### Compose a WHERE statement and then use it in a query
```ts
async function getProductsBy({
  name,
  category,
  maxPrice,
}: {
  name?: string;
  category?: string;
  maxPrice?: number;
}) {
  const filters: SQL[] = [];

  if (name) filters.push(ilike(products.name, name));
  if (category) filters.push(eq(products.category, category));
  if (maxPrice) filters.push(lte(products.price, maxPrice));

  return db
    .select()
    .from(products)
    .where(and(...filters));
}
```

#### Separate subqueries into different variables, and then use them in the main query
```ts
const subquery = db
	.select()
	.from(internalStaff)
	.leftJoin(customUser, eq(internalStaff.userId, customUser.id))
	.as('internal_staff');

const mainQuery = await db
	.select()
	.from(ticket)
	.leftJoin(subquery, eq(subquery.internal_staff.userId, ticket.staffId));
```

#### What's next?
<br/>
<Flex>
  <LinksList 
    title='Access your data'
    links={[
        ["Query", "/docs/rqb"], 
        ["Select", "/docs/select"],
        ["Insert", "/docs/insert"],
        ["Update", "/docs/update"],
        ["Delete", "/docs/delete"],
        ["Filters", "/docs/operators"],
        ["Joins", "/docs/joins"],
        ["sql`` operator", "/docs/sql"],
      ]}
  />
  <LinksList 
    title='Zero to Hero'
    links={[
        ["Migrations", "/docs/migrations"], 
      ]}
  />
</Flex>


Source: https://orm.drizzle.team/docs/pg/delete

import Callout from '@mdx/Callout.astro';
import Section from '@mdx/Section.astro';

# SQL Delete

You can delete all rows in the table:
```typescript copy
await db.delete(users);
```
And you can delete with filters and conditions:
```typescript copy
await db.delete(users).where(eq(users.name, 'Dan'));
```

### Returning

You can delete a row and get it back in PostgreSQL:
```typescript copy
const deletedUser = await db.delete(users)
  .where(eq(users.name, 'Dan'))
  .returning();

// partial return
const deletedUserId = await db.delete(users)
  .where(eq(users.name, "Dan"))
  .returning({ deletedId: users.id });

// deletedUserId: { deletedId: number | null }[]
```
```sql
delete from "users" where "users"."name" = 'Dan' returning "id", "name";

delete from "users" where "users"."name" = 'Dan' returning "id";
```

## WITH DELETE clause

<Callout>
  Check how to use WITH statement with [select](/docs/select#with-clause), [insert](/docs/insert#with-insert-clause), [update](/docs/update#with-update-clause)
</Callout>

Using the `with` clause can help you simplify complex queries by splitting them into smaller subqueries called common table expressions (CTEs):
<Section>
```typescript copy
const averageAmount = db.$with('average_amount').as(
  db.select({ value: sql`avg(${orders.amount})`.as('value') }).from(orders)
);

const result = await db
	.with(averageAmount)
	.delete(orders)
	.where(gt(orders.amount, sql`(select * from ${averageAmount})`))
	.returning({
		id: orders.id
	});
```
```sql
with "average_amount" as (select avg("amount") as "value" from "orders") 
delete from "orders" 
where "orders"."amount" > (select * from "average_amount") 
returning "id"
```
</Section>


Source: https://orm.drizzle.team/docs/pg/drizzle-config-file

import CodeTab from "@mdx/CodeTab.astro";
import CodeTabs from "@mdx/CodeTabs.astro";
import Section from "@mdx/Section.astro";
import Tab from "@mdx/Tab.astro";
import Tabs from "@mdx/Tabs.astro";
import Callout from "@mdx/Callout.astro";
import SchemaFilePaths from "@mdx/SchemaFilePaths.mdx"
import Prerequisites from "@mdx/Prerequisites.astro"
import Dialects from "@mdx/Dialects.mdx"
import Drivers from "@mdx/Drivers.mdx"
import DriversExamples from "@mdx/DriversExamples.mdx"
import Npx from "@mdx/Npx.astro"

# Drizzle Kit configuration file
<Prerequisites>
- Get started with Drizzle and `drizzle-kit` - [read here](/docs/get-started)
- Drizzle schema fundamentals - [read here](/docs/sql-schema-declaration)
- Database connection basics - [read here](/docs/connect-overview)
- Drizzle migrations fundamentals - [read here](/docs/migrations)
- Drizzle Kit [overview](/docs/kit-overview) and [config file](/docs/drizzle-config-file)
</Prerequisites>

Drizzle Kit lets you declare configuration options in `TypeScript` or `JavaScript` configuration files.

<Section>
```plaintext {5}
📦 <project root>
 ├ ...
 ├ 📂 drizzle
 ├ 📂 src
 ├ 📜 drizzle.config.ts
 └ 📜 package.json
```
<CodeTabs items={["drizzle.config.ts", "drizzle.config.js"]}>
<CodeTab>
```ts
import { defineConfig } from "drizzle-kit";

export default defineConfig({
  dialect: "postgresql",
  schema: "./src/schema.ts",
  out: "./drizzle",
});
```
</CodeTab>
<CodeTab>
```js
import { defineConfig } from "drizzle-kit";

export default defineConfig({
  dialect: "postgresql",
  schema: "./src/schema.ts",
  out: "./drizzle",
});
```
</CodeTab>
</CodeTabs>
</Section>

Example of an extended config file
```ts collapsable
import { defineConfig } from "drizzle-kit";

export default defineConfig({
  out: "./drizzle",
  dialect: "postgresql",
  schema: "./src/schema.ts",

  driver: "pglite",
  dbCredentials: {
    url: "./database/",
  },

  extensionsFilters: ["postgis"],
  schemaFilter: "public",
  tablesFilter: "*",

  introspect: {
    casing: "camel",
  },

  migrations: {
    table: "__drizzle_migrations__",
    schema: "drizzle",
  },

  entities: {
    roles: {
      provider: '',
      exclude: [],
      include: []
    }
  },

  breakpoints: true,
  verbose: true,
});
```

### Multiple configuration files
You can have multiple config files in the project, it's very useful when you have multiple database stages or multiple databases or different databases on the same project:
<Npx>
  drizzle-kit generate --config=drizzle-dev.config.ts
  drizzle-kit generate --config=drizzle-prod.config.ts
</Npx>
```plaintext {5-6}
📦 <project root>
 ├ 📂 drizzle
 ├ 📂 src
 ├ 📜 .env
 ├ 📜 drizzle-dev.config.ts
 ├ 📜 drizzle-prod.config.ts
 ├ 📜 package.json
 └ 📜 tsconfig.json
```

### Migrations folder
`out` param lets you define folder for your migrations, it's optional and `drizzle` by default.  
It's very useful since you can have many separate schemas for different databases in the same project 
and have different migration folders for them.  
  
Migration folder contains folders with `.sql` migration files which is used by `drizzle-kit`

<Section>
```plaintext {3}
📦 <project root>
 ├ ...
 ├ 📂 drizzle
 │ ├ 📂 20242409125510_premium_mister_fear
 │ ├ 📜 user.ts 
 │ ├ 📜 post.ts 
 │ └ 📜 comment.ts 
 ├ 📂 src
 ├ 📜 drizzle.config.ts
 └ 📜 package.json
```
```ts {6}
import { defineConfig } from "drizzle-kit";

export default defineConfig({
  dialect: "postgresql",
  schema: "./src/schema/*",
  out: "./drizzle",
});
```
</Section>

## ---

### `dialect`
<rem025/>

Dialect of the database you're using 
|               |                                                 |
| :------------ | :-----------------------------------            |
| type        | <Dialects/>                                     |
| default        | --                                     |
| commands    | `generate`, `push`, `pull`, `studio`,  `migrate`, `up`, `export` |

<rem025/>
```ts {4}
import { defineConfig } from "drizzle-kit";

export default defineConfig({
  dialect: "postgresql", 
});
```


### `schema`
<rem025/>

[`glob`](https://www.digitalocean.com/community/tools/glob?comments=true&glob=/**/*.js&matches=false&tests=//%20This%20will%20match%20as%20it%20ends%20with%20'.js'&tests=/hello/world.js&tests=//%20This%20won't%20match!&tests=/test/some/globs)
 based path to drizzle schema file(s) or folder(s) contaning schema files.
|               |                      |
| :------------ | :-----------------   |
| type          | `string` `string[]` |
| default        | --                    |
| commands      | `generate`, `push`, `export`, `studio`  |

<rem025/>
<SchemaFilePaths />


### `out`
<rem025/>

Defines output folder of your SQL migration files, json snapshots of your schema and `schema.ts` from `drizzle-kit pull` command.
|               |                      |
| :------------ | :-----------------   |
| type          | `string` `string[]` |
| default        | `drizzle`                    |
| commands      | `generate`, `pull`, `migrate`, `check`, `up` |

<rem025/>
```ts {4}
import { defineConfig } from "drizzle-kit";

export default defineConfig({
  out: "./drizzle", 
});
```

### `driver`
<rem025/>

Drizzle Kit automatically picks available database driver from your current project based on the provided `dialect`, 
yet some vendor specific databases require a different subset of connection params.

`driver` option let's you explicitely pick those exceptions drivers.

|               |                      |
| :------------ | :-----------------   |
| type          | `aws-data-api`, `pglite` |
| default        | --                    |
| commands      | `push`, `migrate`, `pull`, `studio`  |

<rem025/>


<CodeTabs items={["AWS Data API", "PGLite"]}>
```ts {6}
import { defineConfig } from "drizzle-kit";

export default defineConfig({
  dialect: "postgresql",
  schema: "./src/schema.ts",
  driver: "aws-data-api",
  dbCredentials: {
    database: "database",
    resourceArn: "resourceArn",
    secretArn: "secretArn",
  },
});
```
```ts {6}
import { defineConfig } from "drizzle-kit";

export default defineConfig({
  dialect: "postgresql",
  schema: "./src/schema.ts",
  driver: "pglite",
  dbCredentials: {
    // inmemory
    url: ":memory:"
    
    // or database folder
    url: "./database/"
  },
});
```
</CodeTabs>

## ---

### `dbCredentials`
<rem025/>

Database connection credentials in a form of `url`, 
`user:password@host:port/db` params or exceptions drivers(<Drivers/>) specific connection options.

|               |                      |
| :------------ | :-----------------   |
| type          | <Dialects/> |
| default       | --                    |
| commands      | `push`, `pull`, `migrate`, `studio` |

<rem025/>

<CodeTabs items={["PostgreSQL","AWS Data API", "PGLite"]}>
<Section>
```ts
import { defineConfig } from 'drizzle-kit'

export default defineConfig({
  dialect: "postgresql",
  dbCredentials: {
    url: "postgres://user:password@host:port/db",
  }
});
```
```ts
import { defineConfig } from 'drizzle-kit'

// via connection params
export default defineConfig({
  dialect: "postgresql",
  dbCredentials: {
    host: "host",
    port: 5432,
    user: "user",
    password: "password",
    database: "dbname",
    ssl: true, // can be boolean | "require" | "allow" | "prefer" | "verify-full" | options from node:tls
  }
});
```
</Section>
```ts
import { defineConfig } from 'drizzle-kit'

export default defineConfig({
  dialect: "postgresql",
  driver: "aws-data-api",
  dbCredentials: {
    database: "database",
    resourceArn: "resourceArn",
    secretArn: "secretArn",
  },
});
```
```ts
import { defineConfig } from 'drizzle-kit'

export default defineConfig({
  dialect: "postgresql",
  driver: "pglite",
  dbCredentials: {
    url: "./database/", // database folder path
  }
});
```
</CodeTabs>

### `migrations`
<rem025/>

When running `drizzle-kit migrate` - drizzle will records about 
successfully applied migrations in your database in log table named `__drizzle_migrations` in `drizzle` schema.

`migrations` config options lets you change both migrations log `table` name and `schema`.

|               |                      |
| :------------ | :-----------------   |
| type          | `{ table: string, schema: string }` |
| default       | `{ table: "__drizzle_migrations", schema: "drizzle" }`                    |
| commands      | `migrate`, `push`, `pull` |

<rem025/>

```ts
export default defineConfig({
  dialect: "postgresql",
  schema: "./src/schema.ts",
  migrations: {
    table: 'my-migrations-table', // `__drizzle_migrations` by default
    schema: 'my_schema', // `drizzle` by default
  },
});
```

### `introspect`
<rem025/>

Configuration for `drizzle-kit pull` command.

`casing` is responsible for in-code column keys casing

|               |                      |
| :------------ | :-----------------   |
| type          | `{ casing: "preserve" \| "camel" }` |
| default       | `{ casing: "camel" }`                    |
| commands      | `pull`   |

<rem025/>

<CodeTabs items={["camel", "preserve"]}>
<Section>
```ts
import * as p from "drizzle-orm/pg-core"

export const users = p.pgTable("users", {
  id: p.serial(),
  firstName: p.text("first-name"),
  lastName: p.text("LastName"),
  email: p.text(),
  phoneNumber: p.text("phone_number"),
});
```
```sql
SELECT a.attname AS column_name, format_type(a.atttypid, a.atttypmod) as data_type FROM pg_catalog.pg_attribute a;
```
``` 
 column_name   | data_type        
---------------+------------------------
 id            | serial
 first-name    | text
 LastName      | text
 email         | text
 phone_number  | text
```
</Section>
<Section>
```ts
import * as p from "drizzle-orm/pg-core"

export const users = p.pgTable("users", {
  id: p.serial(),
  "first-name": p.text("first-name"),
  LastName: p.text("LastName"),
  email: p.text(),
  phone_number: p.text("phone_number"),
});
```
```sql
SELECT a.attname AS column_name, format_type(a.atttypid, a.atttypmod) as data_type FROM pg_catalog.pg_attribute a;
```
``` 
 column_name   | data_type        
---------------+------------------------
 id            | serial
 first-name    | text
 LastName      | text
 email         | text
 phone_number  | text
```
</Section>
</CodeTabs>


## --- 

### `tablesFilter`
<Callout>
If you want to run multiple projects with one database - check out [our guide](/docs/goodies#multi-project-schema).
</Callout>
<rem025/>
`drizzle-kit push` and `drizzle-kit pull` will manage all tables by default.
You can configure list of tables, schemas and extensions via `tablesFilters`, `schemaFilter` and `extensionFilters` options.

`tablesFilter` option lets you specify [`glob`](https://www.digitalocean.com/community/tools/glob?comments=true&glob=/**/*.js&matches=false&tests=//%20This%20will%20match%20as%20it%20ends%20with%20'.js'&tests=/hello/world.js&tests=//%20This%20won't%20match!&tests=/test/some/globs) 
based table names filter, e.g. `["users", "user_info"]` or `"user*"`

|               |                      |
| :------------ | :-----------------   |
| type          | `string` `string[]` |
| default       | --                    |
| commands      | `push` `pull`   |

<rem025/>
```ts
import { defineConfig } from "drizzle-kit";

export default defineConfig({
  dialect: "postgresql",
  tablesFilter: ["users", "posts", "project1_*"],
});
```

### `schemaFilter`


<Callout>
If you want to run multiple projects with one database - check out [our guide](/docs/goodies#multi-project-schema).
</Callout>

`drizzle-kit push` and `drizzle-kit pull` will by default manage all schemas.

`schemaFilter` option lets you specify [`glob`](https://www.digitalocean.com/community/tools/glob?comments=true&glob=/**/*.js&matches=false&tests=//%20This%20will%20match%20as%20it%20ends%20with%20'.js'&tests=/hello/world.js&tests=//%20This%20won't%20match!&tests=/test/some/globs) 
based schema names filter, e.g. `["public", "auth"]` or `"tenant_*"`

|               |                      |
| :------------ | :-----------------   |
| type          | `string[]` |
| commands      | `push` `pull`   |

<rem025/>

```ts
export default defineConfig({
  dialect: "postgresql",
  schemaFilter: ["public", "schema1", "schema2"],
});
```

### `extensionsFilters`
<rem025/>

Some extensions like [`postgis`](https://postgis.net/), when installed on the database, create its own tables in public schema. 
Those tables have to be ignored by `drizzle-kit push` or `drizzle-kit pull`.

`extensionsFilters` option lets you declare list of installed extensions for drizzle kit to ignore their tables in the schema.

|               |                      |
| :------------ | :-----------------   |
| type          | `["postgis"]` |
| default       | `[]`                    |
| commands      | `push` `pull`   |

<rem025/>

```ts
export default defineConfig({
  dialect: "postgresql",
  extensionsFilters: ["postgis"],
});
```

## ---

### `entities`

This configuration is created to set up management settings for specific `entities` in the database. 

For now, it only includes `roles`, but eventually all database entities will migrate here, such as `tables`, `schemas`, `extensions`, `functions`, `triggers`, etc

#### `roles`

<rem025/>

If you are using Drizzle Kit to manage your schema and especially the defined roles, there may be situations where you have some roles that are not defined in the Drizzle schema. 
In such cases, you may want Drizzle Kit to skip those `roles` without the need to write each role in your Drizzle schema and mark it with `.existing()`.

The `roles` option lets you:

- Enable or disable role management with Drizzle Kit.
- Exclude specific roles from management by Drizzle Kit.
- Include specific roles for management by Drizzle Kit.
- Enable modes for providers like `Neon` and `Supabase`, which do not manage their specific roles.
- Combine all the options above

|               |                       |
| :------------ | :-----------------    |
| type          | `boolean \| { provider: "neon" \| "supabase", include: string[], exclude: string[] }`|
| default       | `false`                  |
| commands      | `push` `pull` |

<rem025/>

By default, `drizzle-kit` won't manage roles for you, so you will need to enable that. in `drizzle.config.ts`
```ts
export default defineConfig({
  dialect: "postgresql",
  entities: {
    roles: true
  }
});
```

**You have a role `admin` and want to exclude it from the list of manageable roles**

```ts
// drizzle.config.ts
import { defineConfig } from "drizzle-kit";

export default defineConfig({
  ...
  entities: {
    roles: {
      exclude: ['admin']
    }
  }
});
```

**You have a role `admin` and want to include to the list of manageable roles**

```ts
// drizzle.config.ts
import { defineConfig } from "drizzle-kit";

export default defineConfig({
  ...
  entities: {
    roles: {
      include: ['admin']
    }
  }
});
```

**If you are using `Neon` and want to exclude roles defined by `Neon`, you can use the provider option**

```ts
// drizzle.config.ts
import { defineConfig } from "drizzle-kit";

export default defineConfig({
  ...
  entities: {
    roles: {
      provider: 'neon'
    }
  }
});
```

**If you are using `Supabase` and want to exclude roles defined by `Supabase`, you can use the provider option**

```ts
// drizzle.config.ts
import { defineConfig } from "drizzle-kit";

export default defineConfig({
  ...
  entities: {
    roles: {
      provider: 'supabase'
    }
  }
});
```

<Callout title='important'>
You may encounter situations where Drizzle is slightly outdated compared to new roles specified by database providers, 
so you may need to use both the `provider` option and `exclude` additional roles. You can easily do this with Drizzle:

```ts
// drizzle.config.ts
import { defineConfig } from "drizzle-kit";

export default defineConfig({
  ...
  entities: {
    roles: {
      provider: 'supabase',
      exclude: ['new_supabase_role']
    }
  }
});
```
</Callout>

## ---

### `verbose`
<rem025/>

Print all SQL statements during `drizzle-kit push` command.

|               |                      |
| :------------ | :-----------------   |
| type          | `boolean` |
| default       | `false`                    |
| commands      | `pull`   |

<rem025/>

```ts
export default defineConfig({
  dialect: "postgresql",
  verbose: false,
});
```

### `breakpoints`
<rem025/>

Drizzle Kit will automatically embed `--> statement-breakpoint` into generated SQL migration files, 
that's necessary for databases that do not support multiple DDL alternation statements in one transaction(MySQL and SQLite).

`breakpoints` option flag lets you switch it on and off

|               |                      |
| :------------ | :-----------------   |
| type          | `boolean` |
| default       | `true`                    |
| commands      | `generate` `pull`   |

<rem025/>

```ts
export default defineConfig({
  dialect: "postgresql",
  breakpoints: false,
});
```


Source: https://orm.drizzle.team/docs/pg/drizzle-kit-check

import CodeTab from "@mdx/CodeTab.astro";
import CodeTabs from "@mdx/CodeTabs.astro";
import Section from "@mdx/Section.astro";
import Tab from "@mdx/Tab.astro";
import Tabs from "@mdx/Tabs.astro";
import Callout from "@mdx/Callout.astro";
import Prerequisites from "@mdx/Prerequisites.astro";
import Npm from "@mdx/Npm.astro";
import Npx from "@mdx/Npx.astro";
import Dialects from "@mdx/Dialects.mdx"

# `drizzle-kit check`

<Prerequisites>
- Get started with Drizzle and `drizzle-kit` - [read here](/docs/get-started)
- Drizzle schema fundamentals - [read here](/docs/sql-schema-declaration)
- Database connection basics - [read here](/docs/connect-overview)
- Drizzle migrations fundamentals - [read here](/docs/migrations)
- Drizzle Kit [overview](/docs/kit-overview) and [config file](/docs/drizzle-config-file)
- `drizzle-kit generate` command - [read here](/docs/drizzle-kit-generate)
</Prerequisites>

`drizzle-kit check` command lets you check consistency of your generated SQL migrations history.

That's extremely useful when you have multiple developers working on the project and 
altering database schema on different branches - read more about [migrations for teams](/docs/kit-migrations-for-teams).

<br/>
<hr/>
<br/>

`drizzle-kit check` command requires you to specify `dialect`, 
you can provide it either via [drizzle.config.ts](/docs/drizzle-config-file) config file or via CLI options

<CodeTabs items={["With config file", "As CLI options"]}>
<Section>
```ts {5,8}
// drizzle.config.ts
import { defineConfig } from "drizzle-kit";

export default defineConfig({
  dialect: "postgresql",
});
```
```shell
npx drizzle-kit check
```
</Section>
```shell
npx drizzle-kit check --dialect=postgresql
```
</CodeTabs>

### Multiple configuration files in one project
You can have multiple config files in the project, it's very useful when you have multiple database stages or multiple databases on the same project:
<Npx>
  drizzle-kit check --config=drizzle-dev.config.ts
  drizzle-kit check --config=drizzle-prod.config.ts
</Npx>
```plaintext {5-6}
📦 <project root>
 ├ 📂 drizzle
 ├ 📂 src
 ├ 📜 .env
 ├ 📜 drizzle-dev.config.ts
 ├ 📜 drizzle-prod.config.ts
 ├ 📜 package.json
 └ 📜 tsconfig.json
```

### Ignore conflicts

In case you need `check` command to skip commutativity checks and bypass it, you can use `--ignore-conflicts`. If there is a situation you want to use it, then
there is a big chance that `drizzle-kit` didn't check migrations right and it's a bug. Please report us your case, so we can fix it

```shell
drizzle-kit check --ignore-conflicts
```

### Extended list of configurations
We recommend configuring `drizzle-kit` through [drizzle.config.ts](/docs/drizzle-config-file) file, 
yet you can provide all configuration options through CLI if necessary, e.g. in CI/CD pipelines, etc.
<rem025/>
|           |            |                                                                         |
| :-------- | :--------- | :---------------------------------------------------------------------- |
| `dialect` | `required` | Database dialect you are using. Can be one of <Dialects/> |
| `out`     |            | Migrations folder, default=`./drizzle`                                         |
| `config`  |            | Configuration file path, default=`drizzle.config.ts`                           |
<br/>
<Npx>
drizzle-kit check --dialect=postgresql
drizzle-kit check --dialect=postgresql --out=./migrations-folder
</Npx>


Source: https://orm.drizzle.team/docs/pg/drizzle-kit-export

import CodeTab from "@mdx/CodeTab.astro";
import CodeTabs from "@mdx/CodeTabs.astro";
import Section from "@mdx/Section.astro";
import Tab from "@mdx/Tab.astro";
import Tabs from "@mdx/Tabs.astro";
import Callout from "@mdx/Callout.astro";
import Prerequisites from "@mdx/Prerequisites.astro"
import Npx from "@mdx/Npx.astro";
import SchemaFilePaths from "@mdx/SchemaFilePaths.mdx"
import Dialects from "@mdx/Dialects.mdx"

# `drizzle-kit export` 

<Prerequisites>
- Get started with Drizzle and `drizzle-kit` - [read here](/docs/get-started)
- Drizzle schema fundamentals - [read here](/docs/sql-schema-declaration)
- Database connection basics - [read here](/docs/connect-overview)
- Drizzle migrations fundamentals - [read here](/docs/migrations)
- Drizzle Kit [overview](/docs/kit-overview) and [config file](/docs/drizzle-config-file)
</Prerequisites>


<br/>

`drizzle-kit export` lets you export SQL representation of Drizzle schema and print in console SQL DDL representation on it.
<Callout collapsed="How it works under the hood?">
Drizzle Kit `export` command triggers a sequence of events:
1. It will read through your Drizzle schema file(s) and compose a json snapshot of your schema
2. Based on the current json snapshot it will generate SQL DDL statements
3. Output SQL DDL statements to console
</Callout>

It's designed to cover [codebase first](/docs/migrations) approach of managing Drizzle migrations. 
You can export the SQL representation of the Drizzle schema, allowing external tools like Atlas to handle all the migrations for you

`drizzle-kit export` command requires you to provide both `dialect` and `schema` path options, 
you can set them either via [drizzle.config.ts](/docs/drizzle-config-file) config file or via CLI options
<CodeTabs items={["With config file", "As CLI options"]}>
<Section>
```ts
// drizzle.config.ts
import { defineConfig } from "drizzle-kit";

export default defineConfig({
  dialect: "postgresql",
  schema: "./src/schema.ts",
});
```
```shell
npx drizzle-kit export
```
</Section>

```shell
npx drizzle-kit export --dialect=postgresql --schema=./src/schema.ts
```
</CodeTabs>

### Schema files path
You can have a single `schema.ts` file or as many schema files as you want spread out across the project. 
Drizzle Kit requires you to specify path(s) to them as a [glob](https://www.digitalocean.com/community/tools/glob?comments=true&glob=/**/*.js&matches=false&tests=//%20This%20will%20match%20as%20it%20ends%20with%20'.js'&tests=/hello/world.js&tests=//%20This%20won't%20match!&tests=/test/some/globs) via `schema` configuration option.

<SchemaFilePaths/>

### Multiple configuration files in one project
You can have multiple config files in the project, it's very useful when you have multiple database stages or multiple databases or different databases on the same project:
<Npx>
  drizzle-kit export --config=drizzle-dev.config.ts
  drizzle-kit export --config=drizzle-prod.config.ts
</Npx>
```plaintext {5-6}
📦 <project root>
 ├ 📂 drizzle
 ├ 📂 src
 ├ 📜 .env
 ├ 📜 drizzle-dev.config.ts
 ├ 📜 drizzle-prod.config.ts
 ├ 📜 package.json
 └ 📜 tsconfig.json
```

### Extended list of available configurations
`drizzle-kit export` has a list of cli-only options

<rem025/>

|               |                                                      |
| :--------     | :--------------------------------------------------- |
| `--sql`       | generating SQL representation of Drizzle Schema               |

By default, Drizzle Kit outputs SQL files, but in the future, we want to support different formats

<rem025/>

<Npx>
drizzle-kit export --sql=true
</Npx>

<br/>
<hr/>
<br/>
We recommend configuring `drizzle-kit` through [drizzle.config.ts](/docs/drizzle-config-file) file, 
yet you can provide all configuration options through CLI if necessary, e.g. in CI/CD pipelines, etc.

|               |            |                                                                            |
| :------------ | :-------   | :----------------------------------------------------------------------    |
| `dialect`     | `required` | Database dialect, one of <Dialects/>                                       |
| `schema`      | `required` | Path to typescript schema file(s) or folder(s) with multiple schema files  |
| `config`      |            | Configuration file path, default is `drizzle.config.ts`                    |

### Example
Example of how to export drizzle schema to console with Drizzle schema located in `./src/schema.ts`

We will also place drizzle config file in the `configs` folder.

Let's create config file:

```plaintext {4}
📦 <project root>
 ├ 📂 configs
 │ └ 📜 drizzle.config.ts
 ├ 📂 src
 │ └ 📜 schema.ts
 └ …
```
```ts filename='drizzle.config.ts'
import { defineConfig } from "drizzle-kit";

export default defineConfig({
  dialect: "postgresql",
  schema: "./src/schema.ts",
});
```

```ts filename='schema.ts'
import { pgTable, serial, text } from 'drizzle-orm/pg-core'

export const users = pgTable('users', {
	id: serial('id').primaryKey(),
	email: text('email').notNull(),
	name: text('name')
});
```

Now let's run
```shell
npx drizzle-kit export --config=./configs/drizzle.config.ts
```
And it will successfully output SQL representation of drizzle schema
```bash
CREATE TABLE "users" (
        "id" serial PRIMARY KEY,
        "email" text NOT NULL,
        "name" text
);
```

Source: https://orm.drizzle.team/docs/pg/drizzle-kit-generate

import CodeTab from "@mdx/CodeTab.astro";
import CodeTabs from "@mdx/CodeTabs.astro";
import Section from "@mdx/Section.astro";
import Tab from "@mdx/Tab.astro";
import Tabs from "@mdx/Tabs.astro";
import Callout from "@mdx/Callout.astro";
import Prerequisites from "@mdx/Prerequisites.astro"
import Npx from "@mdx/Npx.astro";
import SchemaFilePaths from "@mdx/SchemaFilePaths.mdx"
import Dialects from "@mdx/Dialects.mdx"

# `drizzle-kit generate` 

<Prerequisites>
- Get started with Drizzle and `drizzle-kit` - [read here](/docs/get-started)
- Drizzle schema fundamentals - [read here](/docs/sql-schema-declaration)
- Database connection basics - [read here](/docs/connect-overview)
- Drizzle migrations fundamentals - [read here](/docs/migrations)
- Drizzle Kit [overview](/docs/kit-overview) and [config file](/docs/drizzle-config-file)
</Prerequisites>


<br/>

`drizzle-kit generate` lets you generate SQL migrations based on your Drizzle schema upon declaration or on subsequent schema changes.
<Callout collapsed="How it works under the hood?">
Drizzle Kit `generate` command triggers a sequence of events:
1. It will read through your Drizzle schema file(s) and compose a json snapshot of your schema
2. It will read through your previous migrations folders and compare current json snapshot to the most recent one
3. Based on json differences it will generate SQL migrations
4. Save `migration.sql` and `snapshot.json` in migration folder under current timestamp

<Section>
```typescript filename="src/schema.ts"
import * as p from "drizzle-orm/pg-core";

export const users = p.pgTable("users", {
  id: p.serial().primaryKey(),
  name: p.text(),
  email: p.text().unique(), 
});
```
```                                  
┌────────────────────────┐                  
│ $ drizzle-kit generate │                  
└─┬──────────────────────┘                  
  │                                           
  └ 1. read previous migration folders
    2. find diff between current and previous schema
    3. prompt developer for renames if necessary
  ┌ 4. generate SQL migration and persist to file
  │    ┌─┴───────────────────────────────────────┐  
  │      📂 drizzle       
  │      └ 📂 20242409125510_premium_mister_fear
  │        ├ 📜 migration.sql
  │        └ 📜 snapshot.json
  v
```
```sql
-- drizzle/20242409125510_premium_mister_fear/migration.sql

CREATE TABLE "users" (
 "id" SERIAL PRIMARY KEY,
 "name" TEXT,
 "email" TEXT UNIQUE
);
```
</Section>
</Callout>

It's designed to cover [code first](/docs/migrations) approach of managing Drizzle migrations. 
You can apply generated migrations using [`drizzle-kit migrate`](/docs/drizzle-kit-migrate), using drizzle-orm's `migrate()`, 
using external migration tools like [bytebase](https://www.bytebase.com/) or running migrations yourself directly on the database. 

`drizzle-kit generate` command requires you to provide both `dialect` and `schema` path options, 
you can set them either via [drizzle.config.ts](/docs/drizzle-config-file) config file or via CLI options
<CodeTabs items={["With config file", "As CLI options"]}>
<Section>
```ts
// drizzle.config.ts
import { defineConfig } from "drizzle-kit";

export default defineConfig({
  dialect: "postgresql",
  schema: "./src/schema.ts",
});
```
```shell
npx drizzle-kit generate
```
</Section>

```shell
npx drizzle-kit generate --dialect=postgresql --schema=./src/schema.ts
```
</CodeTabs>

### Schema files path
You can have a single `schema.ts` file or as many schema files as you want spread out across the project. 
Drizzle Kit requires you to specify path(s) to them as a [glob](https://www.digitalocean.com/community/tools/glob?comments=true&glob=/**/*.js&matches=false&tests=//%20This%20will%20match%20as%20it%20ends%20with%20'.js'&tests=/hello/world.js&tests=//%20This%20won't%20match!&tests=/test/some/globs) via `schema` configuration option.

<SchemaFilePaths/>


### Custom migration file name
You can set custom migration file names by providing `--name` CLI option
```shell
npx drizzle-kit generate --name=init
```
```plaintext {4}
📦 <project root>
 ├ 📂 drizzle
 │ └ 📂 20242409125510_init
 │   ├ 📜 snapshot.json
 │   └ 📜 migration.sql
 ├ 📂 src
 └ …
```

### Multiple configuration files in one project
You can have multiple config files in the project, it's very useful when you have multiple database stages or multiple databases or different databases on the same project:
<Npx>
  drizzle-kit generate --config=drizzle-dev.config.ts
  drizzle-kit generate --config=drizzle-prod.config.ts
</Npx>
```plaintext {5-6}
📦 <project root>
 ├ 📂 drizzle
 ├ 📂 src
 ├ 📜 .env
 ├ 📜 drizzle-dev.config.ts
 ├ 📜 drizzle-prod.config.ts
 ├ 📜 package.json
 └ 📜 tsconfig.json
```

### Custom migrations
You can generate empty migration files to write your own custom SQL migrations 
for DDL alternations currently not supported by Drizzle Kit or data seeding. Extended docs on custom migrations - [see here](/docs/kit-custom-migrations)

```shell
drizzle-kit generate --custom --name=seed-users
```
<Section>
```plaintext {5}
📦 <project root>
 ├ 📂 drizzle
 │ ├ 📂 20242409125510_init
 │ └ 📂 20242409125510_seed-users
 ├ 📂 src
 └ …
```
```sql
-- ./drizzle/20242409125510_seed/migration.sql

INSERT INTO "users" ("name") VALUES('Dan');
INSERT INTO "users" ("name") VALUES('Andrew');
INSERT INTO "users" ("name") VALUES('Dandrew');
```
</Section>

### Ignore conflicts

In case you need `generate` command to skip commutativity checks and bypass it, you can use `--ignore-conflicts`. If there is a situation you want to use it, then
there is a big chance that `drizzle-kit` didn't check migrations right and it's a bug. Please report us your case, so we can fix it

```shell
drizzle-kit generate --ignore-conflicts
```

### Extended list of available configurations
`drizzle-kit generate` has a list of cli-only options

<rem025/>

|               |                                                      |
| :--------     | :--------------------------------------------------- |
| `custom`      | generate empty SQL for custom migration              |
| `name`        | generate migration with custom name                  |
| `ignore-conflicts` | skip commutativity conflict checks, default is `false` |
<rem025/>

<Npx>
drizzle-kit generate --name=init
drizzle-kit generate --name=seed_users --custom
drizzle-kit generate --ignore-conflicts
</Npx>

<br/>
<hr/>
<br/>
We recommend configuring `drizzle-kit` through [drizzle.config.ts](/docs/drizzle-config-file) file, 
yet you can provide all configuration options through CLI if necessary, e.g. in CI/CD pipelines, etc.

|               |            |                                                                            |
| :------------ | :-------   | :----------------------------------------------------------------------    |
| `dialect`     | `required` | Database dialect, one of <Dialects/>                                       |
| `schema`      | `required` | Path to typescript schema file(s) or folder(s) with multiple schema files  |
| `driver`      |            | Driver one of `aws-data-api`, `pglite`   |
| `out`         |            | Migrations output folder, default is `./drizzle`                           |
| `config`      |            | Configuration file path, default is `drizzle.config.ts`                    |
| `breakpoints` |            | SQL statements breakpoints, default is `true`                              |


### Extended example
Example of how to create a custom postgresql migration file named `0001_seed-users.sql` 
with Drizzle schema located in `./src/schema.ts` and migrations folder named `./migrations` instead of default `./drizzle`.

We will also place drizzle config file in the `configs` folder.

Let's create config file:

```plaintext {4}
📦 <project root>
 ├ 📂 migrations
 ├ 📂 configs
 │ └ 📜 drizzle.config.ts
 ├ 📂 src
 └ …
```
```ts filename='drizzle.config.ts'
import { defineConfig } from "drizzle-kit";

export default defineConfig({
  dialect: "postgresql",
  schema: "./src/schema.ts",
  out: "./migrations",
});
```

Now let's run
```shell
npx drizzle-kit generate --config=./configs/drizzle.config.ts --name=seed-users --custom
```
And it will successfully generate
<Section>
```plaintext {6}
📦 <project root>
 ├ …
 ├ 📂 migrations
 │ ├ 📂 20242409125510_init
 │ └ 📂 20242409125510_seed-users
 └ …
```
```sql
-- ./drizzle/20242409125510_seed-users/migration.sql

INSERT INTO "users" ("name") VALUES('Dan');
INSERT INTO "users" ("name") VALUES('Andrew');
INSERT INTO "users" ("name") VALUES('Dandrew');
```
</Section>


Source: https://orm.drizzle.team/docs/pg/drizzle-kit-migrate

import CodeTab from "@mdx/CodeTab.astro";
import CodeTabs from "@mdx/CodeTabs.astro";
import Section from "@mdx/Section.astro";
import Tab from "@mdx/Tab.astro";
import Tabs from "@mdx/Tabs.astro";
import Callout from "@mdx/Callout.astro";
import Prerequisites from "@mdx/Prerequisites.astro";
import Npx from "@mdx/Npx.astro";

# `drizzle-kit migrate`
<Prerequisites>
- Get started with Drizzle and `drizzle-kit` - [read here](/docs/get-started)
- Drizzle schema fundamentals - [read here](/docs/sql-schema-declaration)
- Database connection basics - [read here](/docs/connect-overview)
- Drizzle migrations fundamentals - [read here](/docs/migrations)
- Drizzle Kit [overview](/docs/kit-overview) and [config file](/docs/drizzle-config-file)
- `drizzle-kit generate` command - [read here](/docs/drizzle-kit-generate)
</Prerequisites>
<br/>


`drizzle-kit migrate` lets you apply SQL migrations generated by [`drizzle-kit generate`](/docs/drizzle-kit-generate). 
It's designed to cover [code first(option 3)](/docs/migrations) approach of managing Drizzle migrations. 

<Callout collapsed="How it works under the hood?">
Drizzle Kit `migrate` command triggers a sequence of events:
1. Reads through migration folder and read all `.sql` migration files
2. Connects to the database and fetches entries from drizzle migrations log table
3. Based on previously applied migrations it will decide which new migrations to run
4. Runs SQL migrations and logs applied migrations to drizzle migrations table

<Section>
```plaintext
  ├ 📂 drizzle       
  │ ├ 📂 20242409125510_premium_mister_fear
  │ └ 📂 20242409135510_delicate_professor_xavie
  └ …
```
```plaintext
┌───────────────────────┐                  
│ $ drizzle-kit migrate │                  
└─┬─────────────────────┘                  
  │                                                         ┌──────────────────────────┐                                         
  └ 1. reads migration.sql files in migrations folder       │                          │
    2. fetch migration history from database -------------> │                          │
  ┌ 3. pick previously unapplied migrations <-------------- │         DATABASE         │
  └ 4. apply new migration to the database ---------------> │                          │
                                                            │                          │
                                                            └──────────────────────────┘
[✓] done!        
```
</Section>
</Callout>

`drizzle-kit migrate` command requires you to specify both `dialect` and database connection credentials, 
you can provide them either via [drizzle.config.ts](/docs/drizzle-config-file) config file or via CLI options

<CodeTabs items={["With config file", "As CLI options"]}>
<Section>
```ts {5,8}
// drizzle.config.ts
import { defineConfig } from "drizzle-kit";

export default defineConfig({
  dialect: "postgresql",
  schema: "./src/schema.ts",
  dbCredentials: {
    url: "postgresql://user:password@host:port/dbname"
  },
});
```
```shell
npx drizzle-kit migrate
```
</Section>
```shell
npx drizzle-kit migrate --dialect=postgresql --url=postgresql://user:password@host:port/dbname
```
</CodeTabs>

### Applied migrations log in the database
Upon running migrations Drizzle Kit will persist records about successfully applied migrations in your database. 
It will store them in migrations log table named `__drizzle_migrations` in `drizzle` schema.

You can customise both **table** and **schema** of that table via drizzle config file:
```ts filename="drizzle.config.ts" {8-9}
export default defineConfig({
  dialect: "postgresql",
  schema: "./src/schema.ts",
  dbCredentials: {
    url: "postgresql://user:password@host:port/dbname"
  },
  migrations: {
    table: 'my-migrations-table', // `__drizzle_migrations` by default
    schema: 'public', // `drizzle` by default
  },
});
```

### Multiple configuration files in one project
You can have multiple config files in the project, it's very useful when you have multiple database stages or multiple databases on the same project:
<Npx>
  drizzle-kit migrate --config=drizzle-dev.config.ts
  drizzle-kit migrate --config=drizzle-prod.config.ts
</Npx>
```plaintext {5-6}
📦 <project root>
 ├ 📂 drizzle
 ├ 📂 src
 ├ 📜 .env
 ├ 📜 drizzle-dev.config.ts
 ├ 📜 drizzle-prod.config.ts
 ├ 📜 package.json
 └ 📜 tsconfig.json
```

### Extended example
Let's generate SQL migration and apply it to our database using `drizzle-kit generate` and `drizzle-kit migrate` commands

```plaintext
📦 <project root>
 ├ 📂 drizzle
 ├ 📂 src
 │ ├ 📜 schema.ts
 │ └ 📜 index.ts
 ├ 📜 drizzle.config.ts
 └ …
```
<CodeTabs items={["drizzle.config.ts", "src/schema.ts"]}>
```ts
import { defineConfig } from "drizzle-kit";

export default defineConfig({
  dialect: "postgresql",
  schema: "./src/schema.ts",
  dbCredentials: {
    url: "postgresql://user:password@host:port/dbname"
  },
  migrations: {
    table: 'journal', 
    schema: 'drizzle', 
  },
});
```
```ts 
import * as p from "drizzle-orm/pg-core";

export const users = p.pgTable("users", {
  id: p.serial().primaryKey(),
  name: p.text(),
})
```
</CodeTabs>

Now let's run
```shell
npx drizzle-kit generate --name=init
```
it will generate
<Section>
```plaintext {5}
📦 <project root>
 ├ …
 ├ 📂 migrations
 │ ├ 📂 20242409125510_init
 └ …
```
```sql
-- ./drizzle/0000_init.sql

CREATE TABLE "users"(
  "id" serial primary key,
  "name" text
)
```
</Section>

Now let's run
```shell
npx drizzle-kit migrate
```

and our SQL migration is now successfully applied to the database ✅


Source: https://orm.drizzle.team/docs/pg/drizzle-kit-pull

import CodeTab from "@mdx/CodeTab.astro";
import CodeTabs from "@mdx/CodeTabs.astro";
import Section from "@mdx/Section.astro";
import Tab from "@mdx/Tab.astro";
import Tabs from "@mdx/Tabs.astro";
import Callout from "@mdx/Callout.astro";
import Prerequisites from "@mdx/Prerequisites.astro";
import Drivers from "@mdx/Drivers.mdx"
import Dialects from "@mdx/Dialects.mdx"
import Npm from "@mdx/Npm.astro"
import Npx from "@mdx/Npx.astro"

# `drizzle-kit pull`

<Prerequisites>
- Get started with Drizzle and `drizzle-kit` - [read here](/docs/get-started)
- Drizzle schema fundamentals - [read here](/docs/sql-schema-declaration) 
- Database connection basics - [read here](/docs/connect-overview) 
- Drizzle migrations fundamentals - [read here](/docs/migrations) 
- Drizzle Kit [overview](/docs/kit-overview) and [config file](/docs/drizzle-config-file) docs
</Prerequisites>

`drizzle-kit pull` lets you literally pull(introspect) your existing database schema and generate `schema.ts` drizzle schema file, 
it is designed to cover [database first](/docs/migrations) approach of Drizzle migrations.

<Callout collapsed="How it works under the hood?">
When you run Drizzle Kit `pull` command it will:
1. Pull database schema(DDL) from your existing database
2. Generate `schema.ts` drizzle schema file and save it to `out` folder

<Section>
```
                                  ┌────────────────────────┐      ┌─────────────────────────┐ 
                                  │                        │ <---  CREATE TABLE "users" (
┌──────────────────────────┐      │                        │        "id" SERIAL PRIMARY KEY,
│ ~ drizzle-kit pull       │      │                        │        "name" TEXT,
└─┬────────────────────────┘      │        DATABASE        │        "email" TEXT UNIQUE
  │                               │                        │       );
  └ Pull datatabase schema -----> │                        │
  ┌ Generate Drizzle       <----- │                        │
  │ schema TypeScript file        └────────────────────────┘
  │
  v
```
```typescript
import * as p from "drizzle-orm/pg-core";

export const users = p.pgTable("users", {
  id: p.serial().primaryKey(),
  name: p.text(),
  email: p.text().unique(), 
});
```
</Section>
</Callout>

It is a great approach if you need to manage database schema outside of your TypeScript project or 
you're using database, which is managed by somebody else.

<br/>
<hr/>
<br/>

`drizzle-kit pull` requires you to specify `dialect` and either
database connection `url` or `user:password@host:port/db` params, you can provide them
either via [drizzle.config.ts](/docs/drizzle-config-file) config file or via CLI options:

<CodeTabs items={["With config file", "With CLI options"]}>
<Section>
```ts
// drizzle.config.ts
import { defineConfig } from "drizzle-kit";

export default defineConfig({
  dialect: "postgresql",
  dbCredentials: {
    url: "postgresql://user:password@host:port/dbname",
  },
});
```
```shell
npx drizzle-kit pull
```
</Section>

```shell
npx drizzle-kit pull --dialect=postgresql --url=postgresql://user:password@host:port/dbname
```
</CodeTabs>

### Multiple configuration files in one project

You can have multiple config files in the project, it's very useful when you have multiple database stages or multiple databases or different databases on the same project:

<Npx>
  drizzle-kit pull --config=drizzle-dev.config.ts
  drizzle-kit pull --config=drizzle-prod.config.ts
</Npx>
```plaintext {5-6}
📦 <project root>
 ├ 📂 drizzle
 ├ 📂 src
 ├ 📜 .env
 ├ 📜 drizzle-dev.config.ts
 ├ 📜 drizzle-prod.config.ts
 ├ 📜 package.json
 └ 📜 tsconfig.json
```

### Specifying database driver
Drizzle Kit does not come with a pre-bundled database driver, 
it will automatically pick available database driver from your current project based on the `dialect` - [see discussion](https://github.com/drizzle-team/drizzle-orm/discussions/2203).

Mostly all drivers of the same dialect share the same set of connection params, 
as for exceptions like `aws-data-api`, `pglite` and `d1-http` - you will have to explicitely specify `driver` param.

<CodeTabs items={["AWS Data API", "PGLite", "Cloudflare D1 HTTP"]}>
```ts {6}
import { defineConfig } from "drizzle-kit";

export default defineConfig({
  dialect: "postgresql",
  driver: "aws-data-api",
  dbCredentials: {
    database: "database",
    resourceArn: "resourceArn",
    secretArn: "secretArn",
  },
});
```
```ts {6}
import { defineConfig } from "drizzle-kit";

export default defineConfig({
  dialect: "postgresql",
  driver: "pglite",
  dbCredentials: {
    // inmemory
    url: ":memory:"
    
    // or database folder
    url: "./database/"
  },
});
```
```ts {6}
import { defineConfig } from "drizzle-kit";

export default defineConfig({
  dialect: "sqlite",
  driver: "d1-http",
  dbCredentials: {
    accountId: "accountId",
    databaseId: "databaseId",
    token: "token",
  },
});
```
</CodeTabs>

### Initial pull

You can use the `--init` flag to mark the pulled schema as an applied migration in your database, 
so that all subsequent migrations are diffed against the initial one

```shell
npx drizzle-kit pull --init
```

### Including tables, schemas and extensions
`drizzle-kit pull` will by default manage all tables in all schemas.
You can configure list of tables, schemas and extensions via `tablesFilters`, `schemaFilter` and `extensionFilters` options.

|                     |                                                                                               |
| :------------------ | :-------------------------------------------------------------------------------------------- |
| `tablesFilter`      | `glob` based table names filter, e.g. `["users", "user_info"]` or `"user*"`. Default is `"*"` |
| `schemaFilter`      | `glob` based schema names filter, e.g. `["public", "drizzle"]` or `"drizzle*"`. Default is `"*"`                     |
| `extensionsFilters` | List of installed database extensions, e.g. `["postgis"]`. Default is `[]`                    |
<br/>

Let's configure drizzle-kit to only operate with **all tables** in **public** schema
and let drizzle-kit know that there's a **postgis** extension installed, 
which creates it's own tables in public schema, so drizzle can ignore them.

<Section>
```ts filename="drizzle.config.ts" {9-11}
import { defineConfig } from "drizzle-kit";

export default defineConfig({
  dialect: "postgresql",
  schema: "./src/schema.ts",
  dbCredentials: {
    url: "postgresql://user:password@host:port/dbname",
  },
  extensionsFilters: ["postgis"],
  schemaFilter: ["public"],
  tablesFilter: ["*"],
});
```
```shell
npx drizzle-kit pull
```
</Section>

### Extended list of configurations
We recommend configuring `drizzle-kit` through [drizzle.config.ts](/docs/drizzle-config-file) file, 
yet you can provide all configuration options through CLI if necessary, e.g. in CI/CD pipelines, etc.

|                     |            |                                                                           |
| :------------------ | :--------- | :------------------------------------------------------------------------ |
| `dialect`           | `required` | Database dialect, one of <Dialects/>                                      |
| `driver`            |            | Drivers exceptions <Drivers/>                                             |
| `out`               |            | Migrations output folder path, default is `./drizzle`                     |
| `url`               |            | Database connection string                                                |
| `user`              |            | Database user                                                             |
| `password`          |            | Database password                                                         |
| `host`              |            | Host                                                                      |
| `port`              |            | Port                                                                      |
| `database`          |            | Database name                                                             |
| `config`            |            | Configuration file path, default is `drizzle.config.ts`                          |
| `introspect-casing` |            | Strategy for JS keys creation in columns, tables, etc. `preserve` `camel` |
| `tablesFilter`      |            | Table name filter                                                         |
| `schemaFilter`      |            | Schema name filter. Default: `["*"]`                                 |
| `extensionsFilters` |            | Database extensions internal database filters                             |

<Npx>
drizzle-kit pull --dialect=postgresql --url=postgresql://user:password@host:port/dbname
drizzle-kit pull --dialect=postgresql --driver=pglite url=database/
drizzle-kit pull --dialect=postgresql --tablesFilter='user*' --extensionsFilters=postgis url=postgresql://user:password@host:port/dbname
</Npx>

{/* TODO update gif */}
![](@/assets/gifs/introspect_mysql.gif)


Source: https://orm.drizzle.team/docs/pg/drizzle-kit-push

import CodeTab from "@mdx/CodeTab.astro";
import CodeTabs from "@mdx/CodeTabs.astro";
import Section from "@mdx/Section.astro";
import Tab from "@mdx/Tab.astro";
import Tabs from "@mdx/Tabs.astro";
import Callout from "@mdx/Callout.astro";
import Prerequisites from "@mdx/Prerequisites.astro";
import Npx from "@mdx/Npx.astro";
import SchemaFilePaths from "@mdx/SchemaFilePaths.mdx";
import Drivers from "@mdx/Drivers.mdx"
import Dialects from "@mdx/Dialects.mdx"
import DriversExamples from "@mdx/DriversExamples.mdx"

# `drizzle-kit push`

<Prerequisites>
- Get started with Drizzle and `drizzle-kit` - [read here](/docs/get-started)
- Drizzle schema fundamentals - [read here](/docs/sql-schema-declaration) 
- Database connection basics - [read here](/docs/connect-overview) 
- Drizzle migrations fundamentals - [read here](/docs/migrations) 
- Drizzle Kit [overview](/docs/kit-overview) and [config file](/docs/drizzle-config-file) docs
</Prerequisites>


`drizzle-kit push` lets you literally push your schema and subsequent schema changes directly to the
database while omitting SQL files generation, it's designed to cover [code first](/docs/migrations)
approach of Drizzle migrations.

<Callout collapsed="How it works under the hood?">
When you run Drizzle Kit `push` command it will:
1. Read through your Drizzle schema file(s) and compose a json snapshot of your schema
2. Pull(introspect) database schema 
3. Based on differences between those two it will generate SQL migrations
4. Apply SQL migrations to the database

<Section>
```typescript filename="src/schema.ts"
import * as p from "drizzle-orm/pg-core";

export const users = p.pgTable("users", {
  id: p.serial().primaryKey(),
  name: p.text(),
});
```
```
┌─────────────────────┐                  
│ ~ drizzle-kit push  │                  
└─┬───────────────────┘                  
  │                                           ┌──────────────────────────┐
  └ Pull current datatabase schema ---------> │                          │
                                              │                          │
  ┌ Generate alternations based on diff <---- │         DATABASE         │
  │                                           │                          │
  └ Apply migrations to the database -------> │                          │
                                       │      └──────────────────────────┘
                                       │
  ┌────────────────────────────────────┴────────────────┐
   create table users(id serial primary key, name text);
```
</Section>
</Callout>

It's the best approach for rapid prototyping and we've seen dozens of teams
and solo developers successfully using it as a primary migrations flow in their production applications.
It pairs exceptionally well with blue/green deployment strategy and serverless databases like
[Planetscale](https://planetscale.com), [Neon](https://neon.tech), [Turso](https://turso.tech/drizzle) and others.

<br/>
<hr/>
<br/>


`drizzle-kit push` requires you to specify `dialect`, path to the `schema` file(s) and either
database connection `url` or `user:password@host:port/db` params, you can provide them
either via [drizzle.config.ts](/docs/drizzle-config-file) config file or via CLI options:

<CodeTabs items={["With config file", "With CLI options"]}>
<Section>
```ts
// drizzle.config.ts
import { defineConfig } from "drizzle-kit";

export default defineConfig({
  dialect: "postgresql",
  schema: "./src/schema.ts",
  dbCredentials: {
    url: "postgresql://user:password@host:port/dbname",
  },
});
```
```shell
npx drizzle-kit push
```
</Section>

```shell
npx drizzle-kit push --dialect=postgresql --schema=./src/schema.ts --url=postgresql://user:password@host:port/dbname
```

</CodeTabs>

### Schema files path

You can have a single `schema.ts` file or as many schema files as you want spread out across the project.
Drizzle Kit requires you to specify path(s) to them as a [glob](https://www.digitalocean.com/community/tools/glob?comments=true&glob=/**/*.js&matches=false&tests=//%20This%20will%20match%20as%20it%20ends%20with%20'.js'&tests=/hello/world.js&tests=//%20This%20won't%20match!&tests=/test/some/globs) via `schema` configuration option.

<SchemaFilePaths />

### Multiple configuration files in one project

You can have multiple config files in the project, it's very useful when you have multiple database stages or multiple databases or different databases on the same project:

<Npx>
  drizzle-kit push --config=drizzle-dev.config.ts
  drizzle-kit push --config=drizzle-prod.config.ts
</Npx>
```plaintext {5-6}
📦 <project root>
 ├ 📂 drizzle
 ├ 📂 src
 ├ 📜 .env
 ├ 📜 drizzle-dev.config.ts
 ├ 📜 drizzle-prod.config.ts
 ├ 📜 package.json
 └ 📜 tsconfig.json
```

### Specifying database driver
Drizzle Kit does not come with a pre-bundled database driver, 
it will automatically pick an available database driver from your current project based on the `dialect` - [see discussion](https://github.com/drizzle-team/drizzle-orm/discussions/2203).

Mostly all drivers of the same dialect share the same set of connection params, 
as for exceptions like `aws-data-api`, `pglite` and `d1-http` - you will have to explicitly specify `driver` param.

<DriversExamples/>

### Including tables, schemas and extensions
`drizzle-kit push` will manage all tables and schemas by default.
You can configure list of tables, schemas and extensions via `tablesFilter`, `schemaFilter` and `extensionFilters` options.

|                     |                                                                                               |
| :------------------ | :-------------------------------------------------------------------------------------------- |
| `tablesFilter`      | `glob` based table names filter, e.g. `["users", "user_info"]` or `"user*"`. Default is `"*"` |
| `schemaFilter`      | Schema names filter, e.g. `["public", "drizzle"]`                                             |
| `extensionsFilters` | List of installed database extensions, e.g. `["postgis"]`. Default is `[]`                    |
<br/>

Let's configure drizzle-kit to only operate with **all tables** in **public** schema
and let drizzle-kit know that there's a **postgis** extension installed, 
which creates it's own tables in public schema, so drizzle can ignore them.

<Section>
```ts filename="drizzle.config.ts" {9-11}
import { defineConfig } from "drizzle-kit";

export default defineConfig({
  dialect: "postgresql",
  schema: "./src/schema.ts",
  dbCredentials: {
    url: "postgresql://user:password@host:port/dbname",
  },
  extensionsFilters: ["postgis"],
  schemaFilter: ["public"],
  tablesFilter: ["*"],
});
```
```shell
npx drizzle-kit push
```
</Section>

### Extended list of configurations

`drizzle-kit push` has a list of cli-only options

<rem025/>

|           |                                                                 |
| :-------- | :---------------------------------------------------------------|
| `verbose` | print all SQL statements prior to execution                     |
| `explain` | print the planned SQL changes, without applying them (dry run)  |
| `force`   | auto-accept all data-loss statements                            |
<br/>
<Npx>
drizzle-kit push --explain --verbose --force
</Npx>

<br/>
<hr/>
<br/>
We recommend configuring `drizzle-kit` through [drizzle.config.ts](/docs/drizzle-config-file) file, 
yet you can provide all configuration options through CLI if necessary, e.g. in CI/CD pipelines, etc.

|                     |            |                                                                           |
| :------------------ | :--------- | :------------------------------------------------------------------------ |
| `dialect`           | `required` | Database dialect, one of <Dialects/>                                      |
| `schema`            | `required` | Path to typescript schema file(s) or folder(s) with multiple schema files |
| `driver`            |            | Drivers exceptions, for example `aws-data-api`, `pglite`                  |
| `tablesFilter`      |            | Table name filter                                                         |
| `schemaFilter`      |            | Schema name filter. Default: `["*"]`                                 |
| `extensionsFilters` |            | Database extensions internal database filters                             |
| `url`               |            | Database connection string                                                |
| `user`              |            | Database user                                                             |
| `password`          |            | Database password                                                         |
| `host`              |            | Host                                                                      |
| `port`              |            | Port                                                                      |
| `database`          |            | Database name                                                             |
| `config`            |            | Configuration file path, default=`drizzle.config.ts`                             |

<Npx>
drizzle-kit push dialect=postgresql schema=src/schema.ts url=postgresql://user:password@host:port/dbname
drizzle-kit push dialect=postgresql schema=src/schema.ts driver=pglite url=database/
drizzle-kit push dialect=postgresql schema=src/schema.ts --tablesFilter='user*' --extensionsFilters=postgis url=postgresql://user:password@host:port/dbname
</Npx>


### Extended example
Let's declare drizzle schema in the project and push it to the database via `drizzle-kit push` command

```plaintext
📦 <project root>
 ├ 📂 src
 │ ├ 📜 schema.ts
 │ └ 📜 index.ts
 ├ 📜 drizzle.config.ts
 └ …
```
<CodeTabs items={["drizzle.config.ts", "src/schema.ts"]}>
```ts
import { defineConfig } from "drizzle-kit";

export default defineConfig({
  dialect: "postgresql",
  schema: "./src/schema.ts",
  dbCredentials: {
    url: "postgresql://user:password@host:port/dbname"
  },
});
```
```ts 
import * as p from "drizzle-orm/pg-core";

export const users = p.pgTable("users", {
  id: p.serial().primaryKey(),
  name: p.text(),
})
```
</CodeTabs>

Now let's run
```shell
npx drizzle-kit push
```

it will pull existing(empty) schema from the database and generate SQL migration and apply it under the hood
```sql
CREATE TABLE "users"(
  id serial primary key,
  name text
)
```

DONE ✅


Source: https://orm.drizzle.team/docs/pg/drizzle-kit-studio

import CodeTab from "@mdx/CodeTab.astro";
import CodeTabs from "@mdx/CodeTabs.astro";
import Section from "@mdx/Section.astro";
import Tab from "@mdx/Tab.astro";
import Tabs from "@mdx/Tabs.astro";
import Callout from "@mdx/Callout.astro";
import Prerequisites from "@mdx/Prerequisites.astro";
import Npm from "@mdx/Npm.astro";
import Npx from "@mdx/Npx.astro";


# `drizzle-kit studio`
<Prerequisites>
- Drizzle Kit [overview](/docs/kit-overview) and [config file](/docs/drizzle-config-file)
- Drizzle Studio, our database browser - [read here](/drizzle-studio/overview)
</Prerequisites>

`drizzle-kit studio` command spins up a server for [Drizzle Studio](/drizzle-studio/overview) hosted on [local.drizzle.studio](https://local.drizzle.studio). 
It requires you to specify database connection credentials via [drizzle.config.ts](/docs/drizzle-config-file) config file.

By default it will start a Drizzle Studio server on `127.0.0.1:4983`
<Section>
```ts {6}
// drizzle.config.ts
import { defineConfig } from "drizzle-kit";

export default defineConfig({
  dialect: "postgresql",
  dbCredentials: {
    url: "postgresql://user:password@host:port/dbname"
  },
});
```
```shell
npx drizzle-kit studio
```
</Section>

### Configuring `host` and `port`
By default Drizzle Studio server starts on `127.0.0.1:4983`, 
you can config `host` and `port` via CLI options

<Npx>
drizzle-kit studio --port=3000
drizzle-kit studio --host=0.0.0.0
drizzle-kit studio --host=0.0.0.0 --port=3000
</Npx>


### Logging
You can enable logging of every SQL statement by providing `verbose` flag

<Npx>
drizzle-kit studio --verbose
</Npx>

### Safari and Brave support
Safari and Brave block access to localhost by default. 
You need to install [mkcert](https://github.com/FiloSottile/mkcert) and generate self-signed certificate:

1. Follow the mkcert [installation steps](https://github.com/FiloSottile/mkcert#installation)
2. Run `mkcert -install`
3. Restart your `drizzle-kit studio`

### Other flavours of Drizzle Studio
Apart from `drizzle-kit studio` for local development, Drizzle Studio also comes as a self-hosted
Drizzle Gateway, a Chrome extension for serverless database vendors and an embeddable component
for your own product — check out the [Drizzle Studio overview](/drizzle-studio/overview).

### Limitations
Our hosted version Drizzle Studio is meant to be used for local development and not meant to be used on remote (VPS, etc).

If you want to deploy Drizzle Studio to your VPS — that's what
[Drizzle Gateway](/drizzle-studio/overview#drizzle-gateway) is for.

### Is it open source?
No. Drizzle ORM and Drizzle Kit are fully open sourced, while Studio is not. 

Drizzle Studio for local development is free to use forever to enrich Drizzle ecosystem, 
open sourcing one would've break our ability to provide B2B offerings and monetise it, unfortunately.


Source: https://orm.drizzle.team/docs/pg/drizzle-kit-up

import CodeTab from "@mdx/CodeTab.astro";
import CodeTabs from "@mdx/CodeTabs.astro";
import Section from "@mdx/Section.astro";
import Tab from "@mdx/Tab.astro";
import Tabs from "@mdx/Tabs.astro";
import Callout from "@mdx/Callout.astro";
import Prerequisites from "@mdx/Prerequisites.astro";
import Npx from "@mdx/Npx.astro";
import Dialects from "@mdx/Dialects.mdx"

# `drizzle-kit up`

<Prerequisites>
- Get started with Drizzle and `drizzle-kit` - [read here](/docs/get-started)
- Drizzle schema fundamentals - [read here](/docs/sql-schema-declaration)
- Database connection basics - [read here](/docs/connect-overview)
- Drizzle migrations fundamentals - [read here](/docs/migrations)
- Drizzle Kit [overview](/docs/kit-overview) and [config file](/docs/drizzle-config-file)
- `drizzle-kit generate` command - [read here](/docs/drizzle-kit-generate)
</Prerequisites>

`drizzle-kit up` command lets you upgrade drizzle schema snapshots to a newer version. 
It's required whenever we introduce breaking changes to the json snapshots of the schema and upgrade the internal version.

<br/>
<hr/>
<br/>

`drizzle-kit up` command requires you to specify `dialect` param,
you can provide it either via [drizzle.config.ts](/docs/drizzle-config-file) config file or via CLI options

<CodeTabs items={["With config file", "As CLI options"]}>
<Section>
```ts {5,8}
// drizzle.config.ts
import { defineConfig } from "drizzle-kit";

export default defineConfig({
  dialect: "postgresql",
});
```
```shell
npx drizzle-kit up
```
</Section>
```shell
npx drizzle-kit up --dialect=postgresql
```
</CodeTabs>

### Multiple configuration files in one project
You can have multiple config files in the project, it's very useful when you have multiple database stages or multiple databases on the same project:
<Npx>
  drizzle-kit migrate --config=drizzle-dev.config.ts
  drizzle-kit migrate --config=drizzle-prod.config.ts
</Npx>
```plaintext {5-6}
📦 <project root>
 ├ 📂 drizzle
 ├ 📂 src
 ├ 📜 .env
 ├ 📜 drizzle-dev.config.ts
 ├ 📜 drizzle-prod.config.ts
 ├ 📜 package.json
 └ 📜 tsconfig.json
```

### Extended list of configurations
We recommend configuring `drizzle-kit` through [drizzle.config.ts](/docs/drizzle-config-file) file, 
yet you can provide all configuration options through CLI if necessary, e.g. in CI/CD pipelines, etc.
<rem025/>
|           |            |                                                                         |
| :-------- | :--------- | :---------------------------------------------------------------------- |
| `dialect` | `required` | Database dialect you are using. Can be one of <Dialects/> |
| `out`     |            | Migrations folder, default=`./drizzle`                                  |
| `config`  |            | Configuration file path, default=`drizzle.config.ts`                           |
<br/>
<Npx>
drizzle-kit up --dialect=postgresql
drizzle-kit up --dialect=postgresql --out=./migrations-folder
</Npx>

{/* TODO: update up gif */}
![](@/assets/gifs/up_mysql.gif)



Source: https://orm.drizzle.team/docs/pg/dynamic-query-building

import Callout from '@mdx/Callout.astro';

# Dynamic query building

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
```

In the previous ORM versions, when such restrictions weren't implemented, this example in particular was a source of confusion for many users, as they expected the query builder to "merge" multiple `.where()` calls into a single condition.

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 = 1,
	pageSize: number = 10,
) {
	return qb.limit(pageSize).offset((page - 1) * 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);
```

This is possible, because `PgSelect` and other similar types are specifically designed to be used in dynamic query building. They can only be used in dynamic mode.

Here is the list of all types that can be used as generic parameters in dynamic query building:

| Query  | Type                              |
|:--------|:-----------------------------------|
| Select | `PgSelect` / `PgSelectQueryBuilder` |
| Insert | `PgInsert`                        |
| Update | `PgUpdate`                        |
| Delete | `PgDelete`                        |

<Callout type='info'>
	The `...QueryBuilder` types are for usage with [standalone query builder
	instances](/docs/goodies#standalone-query-builder). DB query builders are
	subclasses of them, so you can use them as well.

    ```ts
    	import { QueryBuilder } from 'drizzle-orm/pg-core';

    	function withFriends<T extends PgSelectQueryBuilder>(qb: T) {
    		return qb.leftJoin(friends, eq(friends.userId, users.id));
    	}

    	const qb = new QueryBuilder();
    	let query = qb.select().from(users).where(eq(users.id, 1)).$dynamic();
    	query = withFriends(query);
    ```

</Callout>


Source: https://orm.drizzle.team/docs/pg/effect-schema

import Npm from '@mdx/Npm.astro';
import Callout from '@mdx/Callout.astro';

# effect-schema

Allows you to generate [effect](https://effect.website/) schemas from Drizzle ORM schemas.

**Features**

- Create a select schema for tables, views and enums.
- Create insert and update schemas for tables.

#### Usage

```ts
import { pgTable, serial, text, timestamp } from 'drizzle-orm/pg-core';
import { createInsertSchema, createSelectSchema, createUpdateSchema } from 'drizzle-orm/effect-schema';
import { Effect, Schema } from "effect";

const users = pgTable('users', {
	id: serial().primaryKey(),
	name: text().notNull(),
	email: text().notNull(),
	role: text({ enum: ['admin', 'user'] }).notNull(),
	createdAt: timestamp('created_at').notNull().defaultNow(),
});

// Schema for inserting a user - can be used to validate API requests
const UserInsert = createInsertSchema(users);

// Schema for updating a user - can be used to validate API requests
const UserUpdate = createUpdateSchema(users);

// Schema for selecting a user - can be used to validate API responses
const UserSelect = createSelectSchema(users);

// Overriding the fields
const UserInsert = createInsertSchema(users, {
	role: Schema.String,
});

// Refining the fields - useful if you want to change the fields before they become nullable/optional in the final schema
const UserInsert = createInsertSchema(users, {
	id: (schema) => schema.check(Schema.isGreaterThanOrEqualTo(0)),
	role: Schema.String,
});

// Usage
const program = Effect.gen(function*() {
	const parsedUser = yield* Schema.decodeUnknownEffect(UserInsert)({
		name: 'John Doe',
		email: 'johndoe@test.com',
		role: 'admin',
	});
});
```

Source: https://orm.drizzle.team/docs/pg/extensions


import Callout from '@mdx/Callout.astro';
import Section from '@mdx/Section.astro';

### `pg_vector`

<Callout>
There is no specific code to create an extension inside the Drizzle schema. We assume that if you are using vector types, 
indexes, and queries, you have a PostgreSQL database with the pg_vector extension installed.
</Callout>

[`pg_vector`](https://github.com/pgvector/pgvector) is open-source vector similarity search for Postgres

Store your vectors with the rest of your data. Supports:

- exact and approximate nearest neighbor search
- single-precision, half-precision, binary, and sparse vectors
- L2 distance, inner product, cosine distance, L1 distance, Hamming distance, and Jaccard distance

#### Column Types

**`vector`**

Store your vectors with the rest of your data

For more info please refer to the official pg_vector docs **[docs.](https://github.com/pgvector/pgvector)**

<Section>
```ts
const table = pgTable('table', {
	embedding: vector({ dimensions: 3 }),
	embedding2: vector({ dimensions: 3 }).default([0, -2, 3])
})
```

```sql
CREATE TABLE "table" (
	"embedding" vector(3),
	"embedding2" vector(3) DEFAULT '[0,-2,3]'
);
```
</Section>

**`halfvec`**

Half-precision vector type, stores dense vectors of half-precision float values

For more info please refer to the official pg_vector docs **[docs.](https://github.com/pgvector/pgvector)**

<Section>
```ts
export const table = pgTable('table', {
	halfvec: halfvec({ dimensions: 3 }),
	halfvec2: halfvec({ dimensions: 3 }).default([0, -2, 3])
})
```

```sql
CREATE TABLE "table" (
	"halfvec" halfvec(3),
	"halfvec2" halfvec(3) DEFAULT '[0,-2,3]'
);
```
</Section>

**`sparsevec`**

Sparse vector type, stores vectors with mostly zero values efficiently

For more info please refer to the official pg_vector docs **[docs.](https://github.com/pgvector/pgvector)**

<Section>
```ts
export const table = pgTable('table', {
	sparsevec: sparsevec({ dimensions: 3 }),
	sparsevec2: sparsevec({ dimensions: 5 }).default(`{1:-1,3:2,5:3}/5`)
})
```

```sql
CREATE TABLE "table" (
	"sparsevec" sparsevec(3),
	"sparsevec2" sparsevec(5) DEFAULT '{1:-1,3:2,5:3}/5'
);
```
</Section>

**`bit`**

Bit string type, used for binary vectors in pgvector

For more info please refer to the official pg_vector **[docs.](https://github.com/pgvector/pgvector)**

<Section>
```ts
export const table = pgTable('table', {
	bit: bit({ dimensions: 5 }),
	bit2: bit({ dimensions: 3 }).default(`101`)
})
```

```sql
CREATE TABLE "table" (
	"bit" bit(5),
	"bit2" bit(3) DEFAULT '101'
);
```
</Section>

#### Indexes

You can now specify indexes for `pg_vector` and utilize `pg_vector` functions for querying, ordering, etc.

Let's take a few examples of `pg_vector` indexes from the `pg_vector` docs and translate them to Drizzle

#### L2 distance, Inner product and Cosine distance for `vector`

```ts
// CREATE INDEX ON items USING hnsw (embedding vector_l2_ops);
// CREATE INDEX ON items USING hnsw (embedding vector_ip_ops);
// CREATE INDEX ON items USING hnsw (embedding vector_cosine_ops);

export const table = pgTable('items', {
    embedding: vector({ dimensions: 3 })
}, (table) => [
  index('l2_index').using('hnsw', table.embedding.op('vector_l2_ops')),
  index('ip_index').using('hnsw', table.embedding.op('vector_ip_ops')),
  index('cosine_index').using('hnsw', table.embedding.op('vector_cosine_ops'))
])
```

#### L2 distance, Inner product and Cosine distance for `halfvec`

```ts
// CREATE INDEX ON items USING hnsw (embedding halfvec_l2_ops);
// CREATE INDEX ON items USING hnsw (embedding halfvec_ip_ops);
// CREATE INDEX ON items USING hnsw (embedding halfvec_cosine_ops);

export const table = pgTable('items', {
	embedding: halfvec({ dimensions: 3 })
}, (table) => [
  index('l2_index').using('hnsw', table.embedding.op('halfvec_l2_ops')),
  index('ip_index').using('hnsw', table.embedding.op('halfvec_ip_ops')),
  index('cosine_index').using('hnsw', table.embedding.op('halfvec_cosine_ops')),
])
```

#### L2 distance, Inner product and Cosine distance for `sparsevec`

```ts
// CREATE INDEX ON items USING hnsw (embedding sparsevec_l2_ops);
// CREATE INDEX ON items USING hnsw (embedding sparsevec_ip_ops);
// CREATE INDEX ON items USING hnsw (embedding sparsevec_cosine_ops);

export const table = pgTable('items', {
	embedding: sparsevec({ dimensions: 3 })
}, (table) => [
  index('l2_index').using('hnsw', table.embedding.op('sparsevec_l2_ops')),
  index('ip_index').using('hnsw', table.embedding.op('sparsevec_ip_ops')),
  index('cosine_index').using('hnsw', table.embedding.op('sparsevec_cosine_ops')),
])
```

#### Hamming distance and Jaccard distance for `bit`

```ts
// CREATE INDEX "hamming_index" ON "items" USING hnsw ("embedding" bit_hamming_ops);
// CREATE INDEX "bit_jaccard_index" ON "items" USING hnsw ("embedding" bit_jaccard_ops);

export const table = pgTable("items", {
    embedding: bit({ dimensions: 3 }),
}, (table) => [
  index("hamming_index").using("hnsw", table.embedding.op("bit_hamming_ops")), 
  index("bit_jaccard_index").using("hnsw", table.embedding.op("bit_jaccard_ops"))
]);
```

#### Helper Functions

For queries, you can use predefined functions for vectors or create custom ones using the SQL template operator.

You can also use the following helpers:

```ts
import { l2Distance, l1Distance, innerProduct, 
          cosineDistance, hammingDistance, jaccardDistance } from 'drizzle-orm'

l2Distance(table.column, [3, 1, 2]) // table.column <-> '[3, 1, 2]'
l1Distance(table.column, [3, 1, 2]) // table.column <+> '[3, 1, 2]'

innerProduct(table.column, [3, 1, 2]) // table.column <#> '[3, 1, 2]'
cosineDistance(table.column, [3, 1, 2]) // table.column <=> '[3, 1, 2]'

hammingDistance(table.column, '101') // table.column <~> '101'
jaccardDistance(table.column, '101') // table.column <%> '101'
```

If `pg_vector` has some other functions to use, you can replicate implementation from existing one we have. Here is how it can be done

```ts
export function l2Distance(
  column: SQLWrapper | AnyColumn,
  value: number[] | string[] | TypedQueryBuilder<any> | string,
): SQL {
  if (is(value, TypedQueryBuilder<any>) || typeof value === 'string') {
    return sql`${column} <-> ${value}`;
  }
  return sql`${column} <-> ${JSON.stringify(value)}`;
}
```

Name it as you wish and change the operator. This example allows for a numbers array, strings array, string, or even a select query. Feel free to create any other type you want or even contribute and submit a PR

#### Examples

Let's take a few examples of `pg_vector` queries from the `pg_vector` docs and translate them to Drizzle

```ts
import { l2Distance } from 'drizzle-orm';

// SELECT * FROM items ORDER BY embedding <-> '[3,1,2]' LIMIT 5;
db.select().from(items).orderBy(l2Distance(items.embedding, [3,1,2]))

// SELECT embedding <-> '[3,1,2]' AS distance FROM items;
db.select({ distance: l2Distance(items.embedding, [3,1,2]) })

// SELECT * FROM items ORDER BY embedding <-> (SELECT embedding FROM items WHERE id = 1) LIMIT 5;
const subquery = db.select({ embedding: items.embedding }).from(items).where(eq(items.id, 1));
db.select().from(items).orderBy(l2Distance(items.embedding, subquery)).limit(5)

// SELECT (embedding <#> '[3,1,2]') * -1 AS inner_product FROM items;
db.select({ innerProduct: sql`(${innerProduct(items.embedding, [3,1,2])}) * -1` }).from(items)

// and more!
```

### `postgis`

<Callout>
There is no specific code to create an extension inside the Drizzle schema. We assume that if you are using postgis types, indexes, and queries, you have a PostgreSQL database with the `postgis` extension installed.
</Callout>

As [PostGIS](https://postgis.net/) website mentions:

> PostGIS extends the capabilities of the PostgreSQL relational database by adding support for storing, indexing, and querying geospatial data.

<Callout type="info">
If you are using the `introspect` or `push` commands with the PostGIS extension and don't want PostGIS tables to be included, you can use [extensionsFilters](/docs/drizzle-config-file#extensionsfilters) to ignore all the PostGIS tables
</Callout>

#### Column Types

**`geometry`**

Store your geometry data with the rest of your data

For more info please refer to the official PostGIS docs **[docs.](https://postgis.net/workshops/postgis-intro/geometries.html)**

```ts
const items = pgTable('items', {
  geo: geometry('geo', { type: 'point' }),
  geoObj: geometry('geo_obj', { type: 'point', mode: 'xy' }),
  geoSrid: geometry('geo_options', { type: 'point', mode: 'xy', srid: 4000 }),
});
```

**mode**

Type `geometry` has 2 modes for mappings from the database: `tuple` and `xy`.

- `tuple` will be accepted for insert and mapped on select to a tuple. So, the database geometry will be typed as [1,2] with drizzle.
- `xy` will be accepted for insert and mapped on select to an object with x, y coordinates. So, the database geometry will be typed as `{ x: 1, y: 2 }` with drizzle

**type**

The current release has a predefined type: `point`, which is the `geometry(Point)` type in the PostgreSQL PostGIS extension. You can specify any string there if you want to use some other type

#### Indexes

With the available Drizzle indexes API, you should be able to write any indexes for PostGIS

**Examples**

```ts
// CREATE INDEX custom_idx ON table USING GIST (geom);

const table = pgTable('table', {
  	geo: geometry({ type: 'point' }),
}, (table) => [
  index('custom_idx').using('gist', table.geo)
])
```


Source: https://orm.drizzle.team/docs/pg/generated-columns

import CodeTabs from '@mdx/CodeTabs.astro';
import CodeTab from '@mdx/CodeTab.astro';
import Callout from '@mdx/Callout.astro';

# Generated Columns

Stored (or persistent) Generated Columns: These columns are computed when a row is inserted or updated and their values are stored in the database. This allows them to be indexed and can improve query performance since the values do not need to be recomputed for each query.

#### Database side
    **Types**: `STORED` only

    **How It Works**
    - Automatically computes values based on other columns during insert or update.

    **Capabilities**
    - Simplifies data access by precomputing complex expressions.
    - Enhances query performance with index support on generated columns.

    **Limitations**
    - Cannot specify default values.
    - Expressions cannot reference other generated columns or include subqueries.
    - Schema changes required to modify generated column expressions.
    - Cannot directly use in primary keys, foreign keys, or unique constraints   

    For more info, please check [PostgreSQL](https://www.postgresql.org/docs/current/ddl-generated-columns.html) docs 

    #### Drizzle side
    In Drizzle you can specify `.generatedAlwaysAs()` function on any column type and add a supported sql query, 
    that will generate this column data for you.

    #### Features 
    This function can accept generated expression in 2 ways:

    **`sql`** tag - if you want drizzle to escape some values for you

    <CodeTab>
    ```ts
    export const test = pgTable("test", {
        generatedName: text("gen_name").generatedAlwaysAs(sql`'hello "world"!'`),
    });
    ```
    ```sql
    CREATE TABLE "test" (
	    "gen_name" text GENERATED ALWAYS AS ('hello "world"!') STORED
    );
    ```
    </CodeTab>

    **`callback`** - if you need to reference columns from a table
    <CodeTab>
    ```ts
    export const test = pgTable("test", {
        name: text("first_name"),
        generatedName: text("gen_name").generatedAlwaysAs(
          (): SQL => sql`'hi, ' || ${test.name} || '!'`
        ),
    });
    ```
    ```sql
    CREATE TABLE "test" (
	    "first_name" text,
	    "gen_name" text GENERATED ALWAYS AS ('hi, ' || "test"."first_name" || '!') STORED
    );
    ```
    </CodeTab>

    **Example** generated columns with full-text search
   <CodeTabs items={["schema.ts"]}>
	<CodeTab>
	```typescript copy {17-19}
    import { SQL, sql } from "drizzle-orm";
    import { customType, index, integer, pgTable, text } from "drizzle-orm/pg-core";

    const tsVector = customType<{ data: string }>({
      dataType() {
        return "tsvector";
      },
    });

    export const test = pgTable(
      "test",
      {
        id: integer("id").primaryKey().generatedAlwaysAsIdentity(),
        content: text("content"),
        contentSearch: tsVector("content_search", {
          dimensions: 3,
        }).generatedAlwaysAs(
          (): SQL => sql`to_tsvector('english', ${test.content})`
        ),
      },
      (t) => [
        index("idx_content_search").using("gin", t.contentSearch)
      ]
    );
    ```
    ```sql {4}
    CREATE TABLE "test" (
    	"id" integer PRIMARY KEY GENERATED ALWAYS AS IDENTITY (sequence name "test_id_seq" INCREMENT BY 1 MINVALUE 1 MAXVALUE 2147483647 START WITH 1 CACHE 1),
    	"content" text,
    	"content_search" tsvector GENERATED ALWAYS AS (to_tsvector('english', "test"."content")) STORED
    );

    CREATE INDEX "idx_content_search" ON "test" USING gin ("content_search");
    ```
    </CodeTab>
   </CodeTabs>


Source: https://orm.drizzle.team/docs/pg/get-started-postgresql

import Tab from '@mdx/Tab.astro';
import Tabs from '@mdx/Tabs.astro';
import Npm from "@mdx/Npm.astro";
import Callout from '@mdx/Callout.astro';
import Steps from '@mdx/Steps.astro';
import AnchorCards from '@mdx/AnchorCards.astro';
import Prerequisites from "@mdx/Prerequisites.astro";
import CodeTabs from "@mdx/CodeTabs.astro";
import WhatsNextPostgres from "@mdx/WhatsNextPostgres.astro";

# Drizzle \<\> PostgreSQL
<Prerequisites>
- Database [connection basics](/docs/connect-overview) with Drizzle
- node-postgres [basics](https://node-postgres.com/)
- postgres.js [basics](https://github.com/porsager/postgres?tab=readme-ov-file#usage)
</Prerequisites>

Drizzle has native support for PostgreSQL connections with the `node-postgres` and `postgres.js` drivers.

There are a few differences between the `node-postgres` and `postgres.js` drivers that we discovered while using both and integrating them with the Drizzle ORM. For example:

- With `node-postgres`, you can install `pg-native` to boost the speed of both `node-postgres` and Drizzle by approximately 10%.
- `node-postgres` supports providing type parsers on a per-query basis without globally patching things. For more details, see [Types Docs](https://node-postgres.com/features/queries#types).
- `postgres.js` uses prepared statements by default, which you may need to opt out of. This could be a potential issue in AWS environments, among others, so please keep that in mind.
- If there's anything else you'd like to contribute, we'd be happy to receive your PRs [here](https://github.com/drizzle-team/drizzle-orm-docs/pulls)

## node-postgres
#### Step 1 - Install packages
<Npm>
 drizzle-orm@rc pg
 -D drizzle-kit@rc @types/pg
</Npm>

#### Step 2 - Initialize the driver and make a query
<CodeTabs items={["node-postgres", "node-postgres with config"]}>
```typescript copy
// Make sure to install the 'pg' package 
import { drizzle } from 'drizzle-orm/node-postgres';

const db = drizzle(process.env.DATABASE_URL);
 
const result = await db.execute('select 1');
```
```typescript copy
// Make sure to install the 'pg' package 
import { drizzle } from 'drizzle-orm/node-postgres';

// You can specify any property from the node-postgres connection options
const db = drizzle({ 
  connection: { 
    connectionString: process.env.DATABASE_URL,
    ssl: true
  }
});
 
const result = await db.execute('select 1');
```
</CodeTabs>

If you need to provide your existing driver:

```typescript copy
// Make sure to install the 'pg' package 
import { drizzle } from "drizzle-orm/node-postgres";
import { Pool } from "pg";

const pool = new Pool({
  connectionString: process.env.DATABASE_URL,
});
const db = drizzle({ client: pool });
 
const result = await db.execute('select 1');
```

## postgres.js
#### Step 1 - Install packages
<Npm>
 drizzle-orm@rc postgres
 -D drizzle-kit@rc
</Npm>

#### Step 2 - Initialize the driver and make a query
<CodeTabs items={["postgres.js", "postgres.js with config"]}>
```typescript copy
import { drizzle } from 'drizzle-orm/postgres-js';

const db = drizzle(process.env.DATABASE_URL);

const result = await db.execute('select 1');
```
```typescript copy
import { drizzle } from 'drizzle-orm/postgres-js';

// You can specify any property from the postgres-js connection options
const db = drizzle({ 
  connection: { 
    url: process.env.DATABASE_URL, 
    ssl: true 
  }
});

const result = await db.execute('select 1');
```
</CodeTabs>

If you need to provide your existing driver:

```typescript copy
// Make sure to install the 'postgres' package
import { drizzle } from 'drizzle-orm/postgres-js';
import postgres from 'postgres';

const queryClient = postgres(process.env.DATABASE_URL);
const db = drizzle({ client: queryClient });

const result = await db.execute('select 1');
```

#### What's next?

<WhatsNextPostgres/>


Source: https://orm.drizzle.team/docs/pg/goodies

import Callout from '@mdx/Callout.astro';
import CodeTabs from '@mdx/CodeTabs.astro';

## Type API
Use Drizzle's type helpers to infer `select` and `insert` models from a PostgreSQL table schema.

```ts
import { serial, text, pgTable } from 'drizzle-orm/pg-core';
import { type InferSelectModel, type InferInsertModel } from 'drizzle-orm';

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

type SelectUser = typeof users.$inferSelect;
type InsertUser = typeof users.$inferInsert;

type SelectUserAlt = InferSelectModel<typeof users>;
type InsertUserAlt = InferInsertModel<typeof users>;
```

## Logging
Enable default query logging by passing `{ logger: true }` to `drizzle`.

```ts
import { drizzle } from "drizzle-orm/...";

const db = drizzle(process.env.DB_URL, { logger: true });
```

You can change the logs destination by creating a `DefaultLogger` instance and providing a custom `writer` to it:
```typescript copy
import { DefaultLogger, type LogWriter } from "drizzle-orm/logger";
import { drizzle } from "drizzle-orm/...";

class MyLogWriter implements LogWriter {
  write(message: string) {
    // Write to file, stdout, etc.
  }
}

const logger = new DefaultLogger({ writer: new MyLogWriter() });
const db = drizzle(process.env.DB_URL, { logger });
```

You can also provide a custom logger.

```ts
import type { Logger } from 'drizzle-orm/logger';
import { drizzle } from "drizzle-orm/...";

class MyLogger implements Logger {
  logQuery(query: string, params: unknown[]): void {
    console.log({ query, params });
  }
}

const db = drizzle(process.env.DB_URL, { logger: new MyLogger() });
```

## Multi-project schema
Use `pgTableCreator` to customize table names when several projects share one database.

```ts
import { serial, text, pgTableCreator } from 'drizzle-orm/pg-core';

const pgTable = pgTableCreator((name) => `project1_${name}`);

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

```

```ts
import { defineConfig } from 'drizzle-kit';

export default defineConfig({
  schema: './src/schema/*',
  out: './drizzle',
  dialect: 'postgresql',
  dbCredentials: {
    url: process.env.DATABASE_URL!,
  },
  tablesFilter: ['project1_*'],
});
```
```sql
CREATE TABLE "project1_users" (
	"id" serial PRIMARY KEY,
	"name" text NOT NULL
);
```

## Printing SQL Query
Print generated SQL from a query with `.toSQL()`.

```ts
const query = db
  .select({ id: users.id, name: users.name })
  .from(users)
  .groupBy(users.id)
  .toSQL();
```

## Raw SQL Queries
Use `db.execute` for raw parametrized SQL.

```ts
import { sql } from 'drizzle-orm';

const statement = sql`select * from ${users} where ${users.id} = ${userId}`;
const result = await db.execute(statement);
```

## Standalone Query Builder
Use the PostgreSQL query builder without creating a database instance.

```ts
import { QueryBuilder } from 'drizzle-orm/pg-core';

const qb = new QueryBuilder();
const query = qb.select().from(users).where(eq(users.name, 'Dan'));
const { sql, params } = query.toSQL();
```

## Get Typed Columns
Use `getColumns` to get a typed column map, which is useful when excluding fields from a selection.

<CodeTabs items={["index.ts", "schema.ts"]}>
```ts
import { getColumns } from 'drizzle-orm';
import { users } from './schema';

const { password, role, ...rest } = getColumns(users);

await db.select({ ...rest }).from(users);
```
```ts
import { serial, text, pgTable } from "drizzle-orm/pg-core";

export const user = pgTable("user", {
  id: serial().primaryKey(),
  name: text(),
  email: text(),
  password: text(),
  role: text().$type<"admin" | "customer">(),
});
```
</CodeTabs>

## Get Table Information
Use `getTableConfig` to inspect PostgreSQL table metadata.

```ts
import { getTableConfig, pgTable } from 'drizzle-orm/pg-core';

export const table = pgTable(...);

const { columns, indexes, foreignKeys, checks, primaryKeys, name, schema } =
  getTableConfig(table);
```

## Compare Object Types
Use `is()` instead of `instanceof` to check Drizzle object types.

```ts
import { Column, is } from 'drizzle-orm';

if (is(value, Column)) {
  // value is narrowed to Column
}
```

## Mock Driver
Use `drizzle.mock()` when you need a typed database object without a real PostgreSQL connection.

```ts
import { drizzle } from 'drizzle-orm/node-postgres';
import { relations } from './relations';

const db = drizzle.mock({ relations });
```


Source: https://orm.drizzle.team/docs/pg/indexes-constraints

import Callout from '@mdx/Callout.astro';
import Section from '@mdx/Section.astro';

# Indexes & Constraints

## Constraints

SQL constraints are the rules enforced on table columns. They are used to prevent invalid data from being entered into the database.

This ensures the accuracy and reliability of your data in the database.

### Default

The `DEFAULT` clause specifies a default value to use for the column if no value provided by the user when doing an `INSERT`.
If there is no explicit `DEFAULT` clause attached to a column definition,
then the default value of the column is `NULL`.

An explicit `DEFAULT` clause may specify that the default value is `NULL`,
a string constant, a blob constant, a signed-number, or any constant expression enclosed in parentheses.

<Section>
    ```typescript
    import { sql } from "drizzle-orm";
    import { integer, uuid, pgTable } from "drizzle-orm/pg-core";

    export const table = pgTable('table', {
      integer1: integer().default(42),
      integer2: integer().default(sql`24`),
      uuid1: uuid().defaultRandom(),
      uuid2: uuid().default(sql`gen_random_uuid()`),
    });
    ```

    ```sql
    CREATE TABLE "table" (
      "integer1" integer DEFAULT 42,
      "integer2" integer DEFAULT 24,
      "uuid1" uuid DEFAULT gen_random_uuid(),
      "uuid2" uuid DEFAULT gen_random_uuid()
    );
    ```
    </Section>

### Not null

By default, a column can hold **NULL** values. The `NOT NULL` constraint enforces a column to **NOT** accept **NULL** values.  

This enforces a field to always contain a value, which means that you cannot insert a new record,
or update a record without adding a value to this field.

<Section>
      ```typescript copy
      import { integer, pgTable } from "drizzle-orm/pg-core";

      export const table = pgTable('table', {
        integer: integer().notNull(),
      });
      ```

      ```sql
      CREATE TABLE "table" (
        "integer" integer NOT NULL
      );
      ```
    </Section>

### Unique

The `UNIQUE` constraint ensures that all values in a column are different.  

Both the `UNIQUE` and `PRIMARY KEY` constraints provide a guarantee for uniqueness for a column or set of columns.

A `PRIMARY KEY` constraint automatically has a `UNIQUE` constraint.  

<Callout type="info" emoji="ℹ️">
  You can have many `UNIQUE` constraints per table, but only one `PRIMARY KEY` constraint per table.
</Callout>

<Section>
      ```typescript copy
      import { integer, text, unique, pgTable } from "drizzle-orm/pg-core";

      export const user = pgTable('user', {
        id: integer().unique(),
      });

      export const table = pgTable('table', {
        id: integer().unique('custom_name'),
      });

      export const composite = pgTable('composite_example', {
        id: integer(),
        name: text(),
      }, (t) => [
        unique().on(t.id, t.name),
        unique('custom_name').on(t.id, t.name)
      ]);

      // In Postgres 15.0+ NULLS NOT DISTINCT is available
      // This example demonstrates both available usages
	export const userNulls = pgTable("user_nulls_example", {
		id: integer(),
		id2: integer().unique("custom_name", { nulls: "not distinct" }),
	}, (t) => [
		unique().on(t.id).nullsNotDistinct()
	]);
      ```

      ```sql
	CREATE TABLE "user" (
		"id" integer UNIQUE
	);

	CREATE TABLE "table" (
		"id" integer CONSTRAINT "custom_name" UNIQUE
	);
	
	CREATE TABLE "composite_example" (
		"id" integer,
		"name" text,
		CONSTRAINT "composite_example_id_name_unique" UNIQUE("id","name"),
		CONSTRAINT "custom_name" UNIQUE("id","name")
	);

	CREATE TABLE "user_nulls_example" (
		"id" integer UNIQUE NULLS NOT DISTINCT,
		"id2" integer CONSTRAINT "custom_name" UNIQUE NULLS NOT DISTINCT
	);
      ```
    </Section>

### Check

The `CHECK` constraint is used to limit the value range that can be placed in a column.

If you define a `CHECK` constraint on a column it will allow only certain values for this column.  

If you define a `CHECK` constraint on a table it can limit the values in certain columns based on values in other columns in the row.

<Section>
      ```typescript copy
      import { sql } from "drizzle-orm";
      import { check, integer, pgTable, text, uuid } from "drizzle-orm/pg-core";

      export const users = pgTable(
        "users",
        {
          id: uuid().defaultRandom().primaryKey(),
          username: text().notNull(),
          age: integer(),
        },
        (table) => [
          check("age_check1", sql`${table.age} > 21`),
        ]
      );
      ```
      ```sql
	  CREATE TABLE "users" (
		"id" uuid PRIMARY KEY DEFAULT gen_random_uuid(),
		"username" text NOT NULL,
		"age" integer,
		CONSTRAINT "age_check1" CHECK ("age" > 21)
	  );
      ```
    </Section>

### Primary Key

The `PRIMARY KEY` constraint uniquely identifies each record in a table.  
Primary keys must contain `UNIQUE` values, and cannot contain `NULL` values.  

A table can have only **ONE** primary key; and in the table, this primary key can consist of single or multiple columns (fields).

<Section>
      ```typescript copy
      import { serial, text, pgTable } from "drizzle-orm/pg-core";

      export const user = pgTable('user', {
        id: serial('id').primaryKey(),
      });

      export const table = pgTable('table', {
        id: text('cuid').primaryKey(),
      });
      ```

      ```sql
	  CREATE TABLE "user" (
		"id" serial PRIMARY KEY
	  );

	  CREATE TABLE "table" (
		"cuid" text PRIMARY KEY
	  );
      ```
    </Section>

### Composite Primary Key

Just like `PRIMARY KEY`, composite primary key uniquely identifies each record in a table using multiple fields.

Drizzle ORM provides a standalone `primaryKey` operator for that:

<Section>
      ```typescript copy {17,19}
      import { serial, text, integer, primaryKey, pgTable } from "drizzle-orm/pg-core";

      export const user = pgTable("user", {
        id: serial("id").primaryKey(),
        name: text("name"),
      });

      export const book = pgTable("book", {
        id: serial("id").primaryKey(),
        name: text("name"),
      });

      export const booksToAuthors = pgTable("books_to_authors", {
        authorId: integer("author_id"),
        bookId: integer("book_id"),
      }, (table) => [
        primaryKey({ columns: [table.bookId, table.authorId] }),
        // Or PK with custom name
        primaryKey({ name: 'custom_name', columns: [table.bookId, table.authorId] }),
      ]);
      ```

      ```sql {6,9}
      ...

      CREATE TABLE "books_to_authors" (
        "author_id" integer,
        "book_id" integer,
        PRIMARY KEY("book_id","author_id")
      );

      ALTER TABLE "books_to_authors" ADD CONSTRAINT "custom_name" PRIMARY KEY("book_id","author_id");
      ```
    </Section>

### Foreign key

The `FOREIGN KEY` constraint is used to prevent actions that would destroy links between tables.
A `FOREIGN KEY` is a field (or collection of fields) in one table, that refers to the `PRIMARY KEY` in another table.
The table with the foreign key is called the child table, and the table with the primary key is called the referenced or parent table.

Drizzle ORM provides several ways to declare foreign keys.
You can declare them in a column declaration statement:

	```typescript copy {11}
	import { serial, text, integer, pgTable } from "drizzle-orm/pg-core";

	export const user = pgTable("user", {
		id: serial("id"),
		name: text("name"),
	});

	export const book = pgTable("book", {
		id: serial("id"),
		name: text("name"),
		authorId: integer("author_id").references(() => user.id)
	});
	```
	```sql {12}
	CREATE TABLE "user" (
		"id" serial,
		"name" text
	);

	CREATE TABLE "book" (
		"id" serial,
		"name" text,
		"author_id" integer
	);

	ALTER TABLE "book" ADD CONSTRAINT "book_author_id_user_id_fkey" FOREIGN KEY ("author_id") REFERENCES "user"("id");
	```



If you want to do a self reference, due to a TypeScript limitations you will have to either explicitly
set return type for reference callback or use a standalone `foreignKey` operator.

	```typescript copy {6,16-18}
    import { serial, text, integer, foreignKey, pgTable, type AnyPgColumn } from "drizzle-orm/pg-core";

    export const user = pgTable("user", {
      id: serial("id"),
      name: text("name"),
      parentId: integer("parent_id").references((): AnyPgColumn => user.id)
    });

    // or
    export const user = pgTable("user", {
      id: serial("id"),
      name: text("name"),
      parentId: integer("parent_id"),
    }, (table) => [
      foreignKey({
        columns: [table.parentId],
        foreignColumns: [table.id],
        name: "custom_fk"
      })
    ]);
    ```
	```sql {7}
	CREATE TABLE "user" (
		"id" serial,
		"name" text,
		"parent_id" integer
	);
	
	ALTER TABLE "user" ADD CONSTRAINT "user_parent_id_user_id_fkey" FOREIGN KEY ("parent_id") REFERENCES "user"("id");
	```

To declare multi-column foreign keys you can use a dedicated `foreignKey` operator:

```typescript copy {15-19}
    import { serial, text, foreignKey, pgTable, AnyPgColumn } from "drizzle-orm/pg-core";

    export const user = pgTable("user", {
      firstName: text("firstName"),
      lastName: text("lastName"),
    }, (table) => [
      primaryKey({ columns: [table.firstName, table.lastName]})
    ]);

    export const profile = pgTable("profile", {
      id: serial("id").primaryKey(),
      userFirstName: text("user_first_name"),
      userLastName: text("user_last_name"),
    }, (table) => [
      foreignKey({
        columns: [table.userFirstName, table.userLastName],
        foreignColumns: [user.firstName, user.lastName],
        name: "custom_fk"
      })
    ])
    ```
	```sql {13}
	CREATE TABLE "user" (
		"firstName" text,
		"lastName" text,
		CONSTRAINT "user_pkey" PRIMARY KEY("firstName","lastName")
	);

	CREATE TABLE "profile" (
		"id" serial PRIMARY KEY,
		"user_first_name" text,
		"user_last_name" text
	);
	
	ALTER TABLE "profile" ADD CONSTRAINT "custom_fk" FOREIGN KEY ("user_first_name","user_last_name") REFERENCES "user"("firstName","lastName");
	```

## Indexes

Drizzle ORM provides API for both `index` and `unique index` declaration:

<Section>
    ```typescript copy {8-9}
    import { serial, text, index, uniqueIndex, pgTable } from "drizzle-orm/pg-core";

    export const user = pgTable("user", {
      id: serial().primaryKey(),
      name: text(),
      email: text(),
    }, (table) => [
      index("name_idx").on(table.name),
      uniqueIndex("email_idx").on(table.email)
    ]);
    ```
    ```sql {5-6}
	CREATE TABLE "user" (
		...
	);

	CREATE INDEX "name_idx" ON "user" ("name");
	CREATE UNIQUE INDEX "email_idx" ON "user" ("email");
    ```
</Section>


Drizzle ORM provides a set of params for index creation:

```ts
// `.on()`
index('name')
  .on(table.column1.asc(), table.column2.nullsFirst(), ...)
  .concurrently()
  .where(sql``)
  .with({ fillfactor: '70' })

// `.onOnly()`
index('name')
  .onOnly(table.column1.asc(), table.column2.nullsFirst(), ...)
  .concurrently()
  .where(sql``)
  .with({ fillfactor: '70' })

// Second Example, with `.using()`
index('name')
  .using('btree', table.column1.asc(), sql`lower(${table.column2})`, table.column1.op('text_ops'))
  .concurrently()
  .where(sql``) // sql expression
  .with({ fillfactor: '70' })
```


Source: https://orm.drizzle.team/docs/pg/insert

import Section from '@mdx/Section.astro';
import Callout from '@mdx/Callout.astro';
import Tab from '@mdx/Tab.astro';
import Tabs from '@mdx/Tabs.astro';

# SQL Insert

<Callout type='info'>
All the values provided to `.values()`are parameterized automatically.
For example, this query:
```ts
await db.insert(users).values({ name: 'Andrew' });
```
will be translated to:
```sql
insert into "users" ("id", "name") values (default, $1) -- params: ['Andrew']
```
</Callout>

<br/>

Drizzle ORM provides you the most SQL-like way to insert rows into the database tables.

Inserting data with Drizzle is extremely straightforward and sql-like. See for yourself:

<Section>
```typescript copy 
await db.insert(users).values({ name: 'Andrew' });
```

```sql
insert into "users" ("id", "name", "age") values (default, 'Andrew', default)
```
</Section>

If you need insert type for a particular table you can use `typeof usersTable.$inferInsert` syntax. 
```typescript copy 
type NewUser = typeof users.$inferInsert;

const insertUser = async (user: NewUser) => {
  return db.insert(users).values(user);
}

const newUser: NewUser = { name: "Alef" };
await insertUser(newUser);
```

## returning

You can insert a row and get it back in PostgreSQL like such:
```typescript copy
await db.insert(users).values({ name: "Dan" }).returning();

// partial return
await db.insert(users).values({ name: "Partial Dan" }).returning({ insertedId: users.id });
```

## Insert multiple rows
```typescript copy
await db.insert(users).values([{ name: 'Andrew' }, { name: 'Dan' }]);
```

## Upserts and conflicts
Drizzle ORM provides simple interfaces for handling upserts and conflicts.

### On conflict do nothing

`onConflictDoNothing` will cancel the insert if there's a conflict:

```typescript copy
await db.insert(users)
  .values({ id: 1, name: 'John' })
  .onConflictDoNothing();

// explicitly specify conflict target
await db.insert(users)
  .values({ id: 1, name: 'John' })
  .onConflictDoNothing({ target: users.id });
```

### On conflict do update

`onConflictDoUpdate` will update the row if there's a conflict:
```typescript
await db.insert(users)
  .values({ id: 1, name: 'Dan' })
  .onConflictDoUpdate({ target: users.id, set: { name: 'John' } });
```

#### `where` clauses

`on conflict do update` can have a `where` clause in two different places -
as part of the conflict target (i.e. for partial indexes) or as part of the `update` clause:

```sql
insert into "employees" ("employee_id", "name") 
values (123, 'John Doe') 
on conflict ("employee_id") where name <> 'John Doe' 
do update set "name" = excluded.name;

insert into "employees" ("employee_id", "name") 
values (123, 'John Doe') 
on conflict ("employee_id") do update set "name" = 'John Doe' 
where name <> 'John Doe';
```

To specify these conditions in Drizzle, you can use `setWhere` and `targetWhere` clauses:

```typescript
await db.insert(employees)
  .values({ employeeId: 123, name: 'John Doe' })
  .onConflictDoUpdate({
    target: employees.employeeId,
    targetWhere: sql`name <> 'John Doe'`,
    set: { name: sql`excluded.name` }
  });

await db.insert(employees)
  .values({ employeeId: 123, name: 'John Doe' })
  .onConflictDoUpdate({
    target: employees.employeeId,
    set: { name: 'John Doe' },
    setWhere: sql`name <> 'John Doe'`
  });
```

Upsert with composite indexes, or composite primary keys for `onConflictDoUpdate`:

```typescript
await db.insert(users)
  .values({ firstName: 'John', lastName: 'Doe' })
  .onConflictDoUpdate({
    target: [users.firstName, users.lastName],
    set: { firstName: 'John1' }
  });
```

## `with insert` clause

<Callout>
  Check how to use WITH statement with [select](/docs/select#with-clause), [update](/docs/update#with-update-clause), [delete](/docs/delete#with-delete-clause)
</Callout>

Using the `with` clause can help you simplify complex queries by splitting them into smaller subqueries called common table expressions (CTEs):
<Section>
```typescript copy
const userCount = db.$with('user_count').as(
	db.select({ value: sql`count(*)`.as('value') }).from(users)
);

const result = await db.with(userCount)
	.insert(users)
	.values([
		{ username: 'user1', admin: sql`((select * from ${userCount}) = 0)` }
	])
	.returning({
		admin: users.admin
	});
```
```sql
with "user_count" as (select count(*) as "value" from "users") 
insert into "users" ("username", "admin") 
values ('user1', ((select * from "user_count") = 0)) 
returning "admin"
```
</Section>

## Insert into ... select

As the PostgreSQL documentation mentions:
<Callout>
A query (SELECT statement) that supplies the rows to be inserted
</Callout>

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

<Tabs items={["Query Builder", "Callback", "SQL template tag"]}>
<Tab>
<Section>
```ts
const insertedEmployees = await db
  .insert(employees)
  .select(
    db.select({ id: users.id, name: users.name }).from(users).where(eq(users.role, 'employee'))
  )
  .returning({
    id: employees.id,
    name: employees.name
  });
```
```ts
const qb = new QueryBuilder();
await db.insert(employees).select(
    qb.select({ id: users.id, name: users.name }).from(users).where(eq(users.role, 'employee'))
);
```
</Section>
</Tab>
<Tab>
<Section>
```ts
await db.insert(employees).select(
    () => db.select({ id: users.id, name: users.name }).from(users).where(eq(users.role, 'employee'))
);
```
```ts
await db.insert(employees).select(
    (qb) => qb.select({ id: users.id, name: users.name }).from(users).where(eq(users.role, 'employee'))
);
```
</Section>
</Tab>
<Tab>
<Section>
```ts
await db.insert(employees).select(
    sql`select "users"."id" as "id", "users"."name" as "name" from "users" where "users"."role" = 'employee'`
);
```
```ts
await db.insert(employees).select(
    () => sql`select "users"."id" as "id", "users"."name" as "name" from "users" where "users"."role" = 'employee'`
);
```
</Section>
</Tab>
</Tabs>


Source: https://orm.drizzle.team/docs/pg/joins

import CodeTabs from '@mdx/CodeTabs.astro';
import CodeTab from '@mdx/CodeTab.astro';
import Section from '@mdx/Section.astro';

# Joins [SQL]
Join clause in SQL is used to combine 2 or more tables, based on related columns between them.
Drizzle ORM joins syntax is a balance between the SQL-likeness and type safety.

## Join types
Drizzle ORM has APIs for `INNER JOIN [LATERAL]`, `FULL JOIN`, `LEFT JOIN [LATERAL]`, `RIGHT JOIN`, `CROSS JOIN [LATERAL]`.
Lets have a quick look at examples based on below table schemas:
```typescript copy
export const users = pgTable("users", {
  id: serial().primaryKey(),
  name: text().notNull(),
  age: integer(),
});

export const pets = pgTable("pets", {
  id: serial().primaryKey(),
  name: text().notNull(),
  ownerId: integer("owner_id")
    .notNull()
    .references(() => users.id),
});
```

### Left Join
<Section>
```typescript copy
const result = await db.select().from(users).leftJoin(pets, eq(users.id, pets.ownerId))
```
```sql
select ... from "users" left join "pets" on "users"."id" = "pets"."owner_id"
```
```typescript
// result type
const result: {
    users: {
        id: number;
        name: string;
        age: number | null;
    };
    pets: {
        id: number;
        name: string;
        ownerId: number;
    } | null;
}[];
```
</Section>

### Left Join Lateral
<Section>
```typescript copy
const subquery = db.select().from(pets).where(gte(users.age, 16)).as('userPets')
const result = await db.select().from(users).leftJoinLateral(subquery, sql`true`)
```
```sql
select ... from "users" left join lateral (select ... from "pets" where "users"."age" >= 16) "userPets" on true
```
```typescript
// result type
const result: {
    users: {
        id: number;
        name: string;
        age: number | null;
    };
    userPets: {
        id: number;
        name: string;
        ownerId: number;
    } | null;
}[];
```
</Section>

### Right Join
<Section>
```typescript copy
const result = await db.select().from(users).rightJoin(pets, eq(users.id, pets.ownerId))
```
```sql
select ... from "users" right join "pets" on "users"."id" = "pets"."owner_id"
```
```typescript
// result type
const result: {
    users: {
        id: number;
        name: string;
        age: number | null;
    } | null;
    pets: {
        id: number;
        name: string;
        ownerId: number;
    };
}[];
```
</Section>

### Inner Join
<Section>
```typescript copy
const result = await db.select().from(users).innerJoin(pets, eq(users.id, pets.ownerId))
```
```sql
select ... from "users" inner join "pets" on "users"."id" = "pets"."owner_id"
```
```typescript
// result type
const result: {
    users: {
        id: number;
        name: string;
        age: number | null;
    };
    pets: {
        id: number;
        name: string;
        ownerId: number;
    };
}[];
```
</Section>

### Inner Join Lateral
<Section>
```typescript copy
const subquery = db.select().from(pets).where(gte(users.age, 16)).as('userPets')
const result = await db.select().from(users).innerJoinLateral(subquery, sql`true`)
```
```sql
select ... from "users" inner join lateral (select ... from "pets" where "users"."age" >= 16) "userPets" on true
```
```typescript
// result type
const result: {
    users: {
        id: number;
        name: string;
        age: number | null;
    };
    userPets: {
        id: number;
        name: string;
        ownerId: number;
    };
}[];
```
</Section>

### Full Join
<Section>
```typescript copy
const result = await db.select().from(users).fullJoin(pets, eq(users.id, pets.ownerId))
```
```sql
select ... from "users" full join "pets" on "users"."id" = "pets"."owner_id"
```
```typescript
// result type
const result: {
    users: {
        id: number;
        name: string;
        age: number | null;
    } | null;
    pets: {
        id: number;
        name: string;
        ownerId: number;
    } | null;
}[];
```
</Section>

### Cross Join
<Section>
```typescript copy
const result = await db.select().from(users).crossJoin(pets)
```
```sql
select ... from "users" cross join "pets"
```
```typescript
// result type
const result: {
    users: {
        id: number;
        name: string;
        age: number | null;
    };
    pets: {
        id: number;
        name: string;
        ownerId: number;
    };
}[];
```
</Section>

### Cross Join Lateral
<Section>
```typescript copy
const subquery = db.select().from(pets).where(gte(users.age, 16)).as('userPets')
const result = await db.select().from(users).crossJoinLateral(subquery)
```
```sql
select ... from "users" cross join lateral (select ... from "pets" where "users"."age" >= 16) "userPets"
```
```typescript
// result type
const result: {
    users: {
        id: number;
        name: string;
        age: number | null;
    };
    userPets: {
        id: number;
        name: string;
        ownerId: number;
    };
}[];
```
</Section>

## Partial select
If you need to select a particular subset of fields or to have a flat response type, Drizzle ORM
supports joins with partial select and will automatically infer return type based on `.select({ ... })` structure.
<Section>
```typescript copy
await db.select({
  userId: users.id,
  petId: pets.id,
}).from(users).leftJoin(pets, eq(users.id, pets.ownerId))
```
```sql
select "users"."id", "pets"."id" from "users" left join "pets" on "users"."id" = "pets"."owner_id"
```
```typescript
// result type
const result: {
  userId: number;
  petId: number | null;
}[];
```
</Section>
You might've noticed that `petId` can be null now, it's because we're left joining and there can be users without a pet.

It's very important to keep in mind when using `sql` operator for partial selection fields and aggregations when needed,
you should to use `sql<type | null>` for proper result type inference, that one is on you!
<Section>
```typescript copy
const result = await db.select({
  userId: users.id,
  petId: pets.id,
  petName1: sql`upper(${pets.name})`,
  petName2: sql<string | null>`upper(${pets.name})`,
  //˄we should explicitly tell 'string | null' in type, since we're left joining that field
}).from(users).leftJoin(pets, eq(users.id, pets.ownerId))
```
```sql
select "users"."id", "pets"."id", upper("pets"."name"), upper("pets"."name")
from "users" 
left join "pets" on "users"."id" = "pets"."owner_id"
```
```typescript
// result type
const result: {
  userId: number;
  petId: number | null;
  petName1: unknown;
  petName2: string | null;
}[];
```
</Section>
To avoid plethora of nullable fields when joining tables with lots of columns we can utilise our **nested select object syntax**,
our smart type inference will make whole object nullable instead of making all table fields nullable!
<Section>
```typescript copy
await db.select({
  userId: users.id,
  userName: users.name,
  pet: {
    id: pets.id,
    name: pets.name,
    upperName: sql<string>`upper(${pets.name})`
  }
}).from(users).fullJoin(pets, eq(users.id, pets.ownerId))
```
```sql
select ... from "users" full join "pets" on "users"."id" = "pets"."owner_id"
```
```typescript
// result type
const result: {
    userId: number | null;
    userName: string | null;
    pet: {
        id: number;
        name: string;
        upperName: string;
    } | null;
}[];
```
</Section>

## Aliases & Selfjoins
Drizzle ORM supports table aliases which comes really handy when you need to do selfjoins.

Lets say you need to fetch users with their parents:
<CodeTabs items={["index.ts", "schema.ts"]}>
<CodeTab>
```typescript copy
import { user } from "./schema";
import { alias } from "drizzle-orm/pg-core";

const parent = alias(user, "parent");
const result = await db
  .select()
  .from(user)
  .leftJoin(parent, eq(parent.id, user.parentId));
```
```sql
select ... from "user" left join "user" "parent" on "parent"."id" = "user"."parent_id"
```
```typescript
// result type
const result: {
    user: {
        id: number;
        name: string;
        parentId: number;
    };
    parent: {
        id: number;
        name: string;
        parentId: number;
    } | null;
}[];
```
</CodeTab>

```typescript
export const user = pgTable("user", {
  id: integer().primaryKey(),
  name: text().notNull(),
  parentId: integer("parent_id").notNull().references((): AnyPgColumn => user.id)
});
```

</CodeTabs>

## Aggregating results
Drizzle ORM delivers name-mapped results from the driver without changing the structure.

You're free to operate with results the way you want, here's an example of mapping many-one relational data:
```typescript
type User = typeof users.$inferSelect;
type Pet = typeof pets.$inferSelect;

const rows = await db
  .select({
    user: users,
    pet: pets,
  })
  .from(users)
  .leftJoin(pets, eq(users.id, pets.ownerId));

const result = rows.reduce<Record<number, { user: User; pets: Pet[] }>>(
  (acc, row) => {
    const user = row.user;
    const pet = row.pet;

    if (typeof acc[user.id] === "undefined") {
      acc[user.id] = { user, pets: [] };
    }	

    if (pet) {
      acc[user.id]!.pets.push(pet);
    }

    return acc;
  },
  {}
);

// result type
const result: Record<number, {
    user: User;
    pets: Pet[];
}>;
```

## Many-to-one example
```typescript
import { pgTable, text, integer } from "drizzle-orm/pg-core";
import { drizzle } from "drizzle-orm/node-postgres";

const cities = pgTable("cities", {
  id: integer().primaryKey(),
  name: text(),
});

const users = pgTable("users", {
  id: integer().primaryKey(),
  name: text(),
  cityId: integer("city_id").references(() => cities.id),
});

const db = drizzle(process.env.DATABASE_URL);

const result = await db.select().from(cities).leftJoin(users, eq(cities.id, users.cityId));
```
## Many-to-many example
```typescript
const users = pgTable("users", {
  id: integer().primaryKey(),
  name: text(),
});

const chatGroups = pgTable("chat_groups", {
  id: integer().primaryKey(),
  name: text(),
});

const usersToChatGroups = pgTable("users_to_chat_groups", {
  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)
await db.select()
  .from(usersToChatGroups)
  .leftJoin(users, eq(usersToChatGroups.userId, users.id))
  .leftJoin(chatGroups, eq(usersToChatGroups.groupId, chatGroups.id))
  .where(eq(chatGroups.id, 1));
```


Source: https://orm.drizzle.team/docs/pg/kit-custom-migrations

import CodeTab from '@mdx/CodeTab.astro';
import CodeTabs from '@mdx/CodeTabs.astro';
import Section from '@mdx/Section.astro';
import Tab from '@mdx/Tab.astro';
import Tabs from '@mdx/Tabs.astro';
import Callout from '@mdx/Callout.astro';
import Npm from '@mdx/Npm.astro';
import Npx from '@mdx/Npx.astro';
import Steps from '@mdx/Steps.astro';
import Prerequisites from "@mdx/Prerequisites.astro"

# Migrations with Drizzle Kit
<Prerequisites>
- Get started with Drizzle and `drizzle-kit` - [read here](/docs/get-started)
- Drizzle schema fundamentals - [read here](/docs/sql-schema-declaration)
- Database connection basics - [read here](/docs/connect-overview)
- Drizzle migrations fundamentals - [read here](/docs/migrations)
- Drizzle Kit [overview](/docs/kit-overview) and [config file](/docs/drizzle-config-file)
- `drizzle-kit generate` command - [read here](/docs/drizzle-kit-generate)
- `drizzle-kit migrate` command - [read here](/docs/drizzle-kit-migrate)
</Prerequisites>

Drizzle lets you generate empty migration files to write your own custom SQL migrations 
for DDL alternations currently not supported by Drizzle Kit or data seeding, which you can then run with [`drizzle-kit migrate`](/docs/drizzle-kit-migrate) command.

```shell
drizzle-kit generate --custom --name=seed-users
```
<Section>
```plaintext {4}
📦 <project root>
 ├ 📂 drizzle
 │ ├ 📂 20242409125510_init_sql
 │ └ 📂 20242409135510_seed-users
 ├ 📂 src
 └ …
```
```sql
-- ./drizzle/20242409135510_seed-users.sql

INSERT INTO "users" ("name") VALUES('Dan');
INSERT INTO "users" ("name") VALUES('Andrew');
INSERT INTO "users" ("name") VALUES('Dandrew');
```
</Section>

### Running JavaScript and TypeScript migrations
We will add ability to run custom JavaScript and TypeScript migration/seeding scripts in the upcoming release, you can follow [github discussion](https://github.com/drizzle-team/drizzle-orm/discussions/2832).

Source: https://orm.drizzle.team/docs/pg/kit-overview

import CodeTab from '@mdx/CodeTab.astro';
import CodeTabs from '@mdx/CodeTabs.astro';
import Section from '@mdx/Section.astro';
import Tab from '@mdx/Tab.astro';
import Tabs from '@mdx/Tabs.astro';
import Callout from '@mdx/Callout.astro';
import Npm from '@mdx/Npm.astro';
import Npx from '@mdx/Npx.astro';
import Steps from '@mdx/Steps.astro';
import Prerequisites from "@mdx/Prerequisites.astro"

# Migrations with Drizzle Kit
<Prerequisites>
- Get started with Drizzle and `drizzle-kit` - [read here](/docs/get-started)
- Drizzle schema fundamentals - [read here](/docs/sql-schema-declaration)
- Database connection basics - [read here](/docs/connect-overview)
- Drizzle migrations fundamentals - [read here](/docs/migrations)
</Prerequisites>


**Drizzle Kit** is a CLI tool for managing SQL database migrations with Drizzle.
<Npm>
  -D drizzle-kit
</Npm>
<Callout type="warning">
Make sure to first go through Drizzle [get started](/docs/get-started) and [migration fundamentals](/docs/migrations) and pick SQL migration flow that suits your business needs best. 
</Callout>

Based on your schema, Drizzle Kit let's you generate and run SQL migration files, 
push schema directly to the database, pull schema from database, spin up drizzle studio and has a couple of utility commands.
<Npx>
drizzle-kit generate
drizzle-kit migrate
drizzle-kit push
drizzle-kit pull
drizzle-kit check
drizzle-kit up
drizzle-kit studio
drizzle-kit export
</Npx>


|                                                      |                                                                                                                                                                    |
| :--------------------------------------------------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| [`drizzle-kit generate`](/docs/drizzle-kit-generate) | lets you generate SQL migration files based on your Drizzle schema either upon declaration or on subsequent changes, [see here](/docs/drizzle-kit-generate).       |
| [`drizzle-kit migrate`](/docs/drizzle-kit-migrate)   | lets you apply generated SQL migration files to your database, [see here](/docs/drizzle-kit-migrate).                                                              |
| [`drizzle-kit pull`](/docs/drizzle-kit-pull)         | lets you pull(introspect) database schema, convert it to Drizzle schema and save it to your codebase, [see here](/docs/drizzle-kit-pull)                           |
| [`drizzle-kit push`](/docs/drizzle-kit-push)         | lets you push your Drizzle schema to database either upon declaration or on subsequent schema changes, [see here](/docs/drizzle-kit-push)                          |
| [`drizzle-kit studio`](/docs/drizzle-kit-studio)     | will connect to your database and spin up proxy server for Drizzle Studio which you can use for convenient database browsing, [see here](/docs/drizzle-kit-studio) |
| [`drizzle-kit check`](/docs/drizzle-kit-check)       | will walk through all generate migrations and check for any race conditions(collisions) of generated migrations, [see here](/docs/drizzle-kit-check)               |
| [`drizzle-kit up`](/docs/drizzle-kit-up)             | used to upgrade snapshots of previously generated migrations, [see here](/docs/drizzle-kit-up)                                                                     |
| [`drizzle-kit export`](/docs/drizzle-kit-export)     | used to convert a TypeScript schema into raw SQL DDL and print it out [see here](/docs/drizzle-kit-export)                                                                     |
<br/>

Drizzle Kit is configured through [drizzle.config.ts](/docs/drizzle-config-file) configuration file or via CLI params.<br/>
It's required to at least provide SQL `dialect` and `schema` path for Drizzle Kit to know how to generate migrations.
```
📦 <project root>
 ├ 📂 drizzle
 ├ 📂 src
 ├ 📜 .env
 ├ 📜 drizzle.config.ts  <--- Drizzle config file
 ├ 📜 package.json
 └ 📜 tsconfig.json
```

<CodeTabs items={["simple config", "extended config"]}>
```ts
import { defineConfig } from "drizzle-kit";

export default defineConfig({
  dialect: "postgresql",
  schema: "./src/schema.ts",
});
```
```ts
import { defineConfig } from "drizzle-kit";

export default defineConfig({
  out: "./drizzle",
  dialect: "postgresql",
  schema: "./schema.ts",

  entities: {
    roles: {
      exclude: ["admin"],
      include: ["user"],
      provider: "supabase",
    },
  },

  driver: "pglite",
  dbCredentials: {
    url: "./database/",
  },

  extensionsFilters: ["postgis"],
  schemaFilter: "public",
  tablesFilter: "*",

  introspect: {
    casing: "camel",
  },

  migrations: {
    table: "__drizzle_migrations__",
    schema: "public",
  },

  breakpoints: true,
  verbose: true,
});
```
</CodeTabs>

You can provide Drizzle Kit config path via CLI param, it's very useful when you have multiple database stages or multiple databases or different databases on the same project:

<Npx>
  drizzle-kit push --config=drizzle-dev.drizzle.config
  drizzle-kit push --config=drizzle-prod.drizzle.config
</Npx>
```plaintext {5-6}
📦 <project root>
 ├ 📂 drizzle
 ├ 📂 src
 ├ 📜 .env
 ├ 📜 drizzle-dev.config.ts
 ├ 📜 drizzle-prod.config.ts
 ├ 📜 package.json
 └ 📜 tsconfig.json
```


Source: https://orm.drizzle.team/docs/pg/migrations

import Callout from '@mdx/Callout.astro';
import Steps from '@mdx/Steps.astro';
import CodeTab from '@mdx/CodeTab.astro';
import CodeTabs from '@mdx/CodeTabs.astro';
import Section from '@mdx/Section.astro';
import Tab from '@mdx/Tab.astro';
import Tabs from '@mdx/Tabs.astro';
import Npm from '@mdx/Npm.astro';
import Tag from '@mdx/Tag.astro'


# Drizzle migrations fundamentals

SQL databases require you to specify a **strict schema** of entities you're going to store upfront 
and if (when) you need to change the shape of those entities - you will need to do it via **schema migrations**.

There're multiple production grade ways of managing database migrations. 
Drizzle is designed to perfectly suits all of them, regardless of you going **database first** or **codebase first**.

**Database first** is when your database schema is a source of truth. You manage your database schema either directly on the database or 
via database migration tools and then you pull your database schema to your codebase application level entities.  
 
**Codebase first** is when database schema in your codebase is a source of truth and is under version control. You declare and manage your database schema in JavaScript/TypeScript
and then you apply that schema to the database itself either with Drizzle, directly or via external migration tools. 

#### How can Drizzle help?
We've built [**drizzle-kit**](/docs/kit-overview) - CLI app for managing migrations with Drizzle. 
```shell
drizzle-kit migrate
drizzle-kit generate
drizzle-kit push
drizzle-kit pull
drizzle-kit export
```
It is designed to let you choose how to approach migrations based on your current business demands. 

It fits in both database and codebase first approaches, it lets you **push your schema** or **generate SQL migration** files or **pull the schema** from database. 
It is perfect wether you work alone or in a team.
<br/>

<hr/>
<rem/>

**Now let's pick the best option for your project:**
<rem/>

<Tag style="font-size: 12px">**Option 1**</Tag>
> I manage database schema myself using external migration tools or by running SQL migrations directly on my database.
> From Drizzle I just need to get current state of the schema from my database and save it as TypeScript schema file.

<Callout collapsed="Expand details">
That's a **database first** approach. You have your database schema as a **source of truth** and 
Drizzle lets you pull database schema to TypeScript using [`drizzle-kit pull`](/docs/drizzle-kit-pull) command.

<Section>
```
                                  ┌────────────────────────┐      ┌─────────────────────────┐ 
                                  │                        │ <---  CREATE TABLE "users" (
┌──────────────────────────┐      │                        │        "id" SERIAL PRIMARY KEY,
│ ~ drizzle-kit pull       │      │                        │        "name" TEXT,
└─┬────────────────────────┘      │        DATABASE        │        "email" TEXT UNIQUE
  │                               │                        │       );
  └ Pull datatabase schema -----> │                        │
  ┌ Generate Drizzle       <----- │                        │
  │ schema TypeScript file        └────────────────────────┘
  │
  v
```
```typescript
import * as p from "drizzle-orm/pg-core";

export const users = p.pgTable("users", {
  id: p.serial().primaryKey(),
  name: p.text(),
  email: p.text().unique(),
});
```
</Section>
</Callout>

<rem/>
<rem/>
<rem/>

<Tag style="font-size: 12px">**Option 2**</Tag>
> I want to have database schema in my TypeScript codebase, 
> I don't wanna deal with SQL migration files.  
> I want Drizzle to "push" my schema directly to the database

<Callout collapsed="Expand details">
That's a **codebase first** approach. You have your TypeScript Drizzle schema as a **source of truth** and 
Drizzle lets you push schema changes to the database using [`drizzle-kit push`](/docs/drizzle-kit-push) command.

That's the best approach for rapid prototyping and we've seen dozens of teams 
and solo developers successfully using it as a primary migrations flow in their production applications.

<Section>
```typescript {6} filename="src/schema.ts"
import * as p from "drizzle-orm/pg-core";

export const users = p.pgTable("users", {
  id: p.serial().primaryKey(),
  name: p.text(),
  email: p.text().unique(), // <--- added column
});
```
```
Add column to `users` table                                                                          
┌──────────────────────────┐                  
│ + email: text().unique() │                  
└─┬────────────────────────┘                  
  │                                           
  v                                           
┌──────────────────────────┐                  
│ ~ drizzle-kit push       │                  
└─┬────────────────────────┘                  
  │                                           ┌──────────────────────────┐
  └ Pull current datatabase schema ---------> │                          │
                                              │                          │
  ┌ Generate alternations based on diff <---- │         DATABASE         │
  │                                           │                          │
  └ Apply migrations to the database -------> │                          │
                                       │      └──────────────────────────┘
                                       │
  ┌────────────────────────────────────┴───────────────────────────────┐
   ALTER TABLE "users" ADD COLUMN "email" text;
   ALTER TABLE "users" ADD CONSTRAINT "users_email_key" UNIQUE("email"); 
```
</Section>
</Callout>

<rem/>
<rem/>
<rem/>

<Tag style="font-size: 12px">**Option 3**</Tag>
> I want to have database schema in my TypeScript codebase, 
> I want Drizzle to generate SQL migration files for me and apply them to my database

<Callout collapsed="Expand details">
That's a **codebase first** approach. You have your TypeScript Drizzle schema as a source of truth and 
Drizzle lets you generate SQL migration files based on your schema changes with [`drizzle-kit generate`](/docs/drizzle-kit-generate)
and then apply them to the database with [`drizzle-kit migrate`](/docs/drizzle-kit-migrate) commands. 
<Section>
```typescript filename="src/schema.ts"
import * as p from "drizzle-orm/pg-core";

export const users = p.pgTable("users", {
  id: p.serial().primaryKey(),
  name: p.text(),
  email: p.text().unique(),
});
```
```                                  
┌────────────────────────┐                  
│ $ drizzle-kit generate │                  
└─┬──────────────────────┘                  
  │                                           
  └ 1. read previous migration folders
    2. find diff between current and previous schema
    3. prompt developer for renames if necessary
  ┌ 4. generate SQL migration and persist to file
  │    ┌─┴───────────────────────────────────────┐  
  │      📂 drizzle       
  │      └ 📂 20242409125510_premium_mister_fear
  │        ├ 📜 snapshot.json
  │        └ 📜 migration.sql
  v
```
```sql
-- drizzle/20242409125510_premium_mister_fear/migration.sql

CREATE TABLE "users" (
 "id" SERIAL PRIMARY KEY,
 "name" TEXT,
 "email" TEXT UNIQUE
);
```
```
┌───────────────────────┐                  
│ $ drizzle-kit migrate │                  
└─┬─────────────────────┘                  
  │                                                         ┌──────────────────────────┐                                         
  └ 1. read migration.sql files in migrations folder        │                          │
    2. fetch migration history from database -------------> │                          │
  ┌ 3. pick previously unapplied migrations <-------------- │         DATABASE         │
  └ 4. apply new migration to the database ---------------> │                          │
                                                            │                          │
                                                            └──────────────────────────┘
[✓] done!                                                 
```
</Section>
</Callout>

<rem/>
<rem/>
<rem/>

<Tag style="font-size: 12px">**Option 4**</Tag>
> I want to have database schema in my TypeScript codebase,
> I want Drizzle to generate SQL migration files for me and I want Drizzle to apply them during runtime

<Callout collapsed="Expand details">
That's a **codebase first** approach. You have your TypeScript Drizzle schema as a source of truth and 
Drizzle lets you generate SQL migration files based on your schema changes with [`drizzle-kit generate`](/docs/drizzle-kit-generate) and then 
you can apply them to the database during runtime of your application.

This approach is widely used for **monolithic** applications when you apply database migrations 
during zero downtime deployment and rollback DDL changes if something fails. 
This is also used in **serverless** deployments with migrations running in **custom resource** once during deployment process.

<Section>
```typescript filename="src/schema.ts"
import * as p from "drizzle-orm/pg-core";

export const users = p.pgTable("users", {
  id: p.serial().primaryKey(),
  name: p.text(),
  email: p.text().unique(),
});
```
```                                  
┌────────────────────────┐                  
│ $ drizzle-kit generate │                  
└─┬──────────────────────┘                  
  │                                           
  └ 1. read previous migration folders
    2. find diff between current and previous schema
    3. prompt developer for renames if necessary
  ┌ 4. generate SQL migration and persist to file
  │    ┌─┴───────────────────────────────────────┐  
  │      📂 drizzle       
  │      └ 📂 20242409125510_premium_mister_fear
  │        ├ 📜 snapshot.json
  │        └ 📜 migration.sql
  v
```
```sql
-- drizzle/20242409125510_premium_mister_fear/migration.sql

CREATE TABLE "users" (
 "id" SERIAL PRIMARY KEY,
 "name" TEXT,
 "email" TEXT UNIQUE
);
```
```ts
// index.ts
import { drizzle } from "drizzle-orm/node-postgres"
import { migrate } from 'drizzle-orm/node-postgres/migrator';

const db = drizzle(process.env.DATABASE_URL);

await migrate(db);
```
```
┌───────────────────────┐                  
│ npx tsx src/index.ts  │                  
└─┬─────────────────────┘                  
  │                                                      
  ├ 1. init database connection                             ┌──────────────────────────┐                                         
  └ 2. read migration.sql files in migrations folder        │                          │
    3. fetch migration history from database -------------> │                          │
  ┌ 4. pick previously unapplied migrations <-------------- │         DATABASE         │
  └ 5. apply new migration to the database ---------------> │                          │
                                                            │                          │
                                                            └──────────────────────────┘
[✓] done!                                                 
```
</Section>
</Callout>

<rem/>
<rem/>
<rem/>

<Tag style="font-size: 12px">**Option 5**</Tag>
> I want to have database schema in my TypeScript codebase,
> I want Drizzle to generate SQL migration files for me,
> but I will apply them to my database myself or via external migration tools 

<Callout collapsed="Expand details">
That's a **codebase first** approach. You have your TypeScript Drizzle schema as a source of truth and 
Drizzle lets you generate SQL migration files based on your schema changes with [`drizzle-kit generate`](/docs/drizzle-kit-generate) and then 
you can apply them to the database either directly or via external migration tools.

<Section>
```typescript filename="src/schema.ts"
import * as p from "drizzle-orm/pg-core";

export const users = p.pgTable("users", {
  id: p.serial().primaryKey(),
  name: p.text(),
  email: p.text().unique(),
});
```
```                                  
┌────────────────────────┐                  
│ $ drizzle-kit generate │                  
└─┬──────────────────────┘                  
  │                                           
  └ 1. read previous migration folders
    2. find diff between current and previous scheama
    3. prompt developer for renames if necessary
  ┌ 4. generate SQL migration and persist to file
  │    ┌─┴───────────────────────────────────────┐  
  │      📂 drizzle       
  │      └ 📂 20242409125510_premium_mister_fear
  │        ├ 📜 snapshot.json
  │        └ 📜 migration.sql
  v
```
```sql
-- drizzle/20242409125510_premium_mister_fear/migration.sql

CREATE TABLE "users" (
 "id" SERIAL PRIMARY KEY,
 "name" TEXT,
 "email" TEXT UNIQUE
);
```
```
┌───────────────────────────────────┐                  
│ (._.) now you run your migrations │           
└─┬─────────────────────────────────┘  
  │
 directly to the database
  │                                         ┌────────────────────┐
  ├────────────────────────────────────┬───>│                    │  
  │                                    │    │      Database      │           
 or via external tools                 │    │                    │   
  │                                    │    └────────────────────┘
  │  ┌────────────────────┐            │      
  └──│ Bytebase           ├────────────┘         
     ├────────────────────┤  
     │ Liquibase          │
     ├────────────────────┤ 
     │ Atlas              │
     ├────────────────────┤ 
     │ etc…               │
     └────────────────────┘

[✓] done!                                                 
```
</Section>
</Callout>

<rem/>
<rem/>
<rem/>

<Tag style="font-size: 12px">**Option 6**</Tag>
> I want to have database schema in my TypeScript codebase,
> I want Drizzle to output the SQL representation of my Drizzle schema to the console,
> and I will apply them to my database via [Atlas](https://atlasgo.io/guides/orms/drizzle)

<Callout collapsed="Expand details">
That's a **codebase first** approach. You have your TypeScript Drizzle schema as a source of truth and 
Drizzle lets you export SQL statements based on your schema changes with [`drizzle-kit export`](/docs/drizzle-kit-generate) and then 
you can apply them to the database via [Atlas](https://atlasgo.io/guides/orms/drizzle) or other external SQL migration tools.

<Section>
```typescript filename="src/schema.ts"
import * as p from "drizzle-orm/pg-core";

export const users = p.pgTable("users", {
  id: p.serial().primaryKey(),
  name: p.text(),
  email: p.text().unique(),
});
```
```                                  
┌────────────────────────┐                  
│ $ drizzle-kit export   │                  
└─┬──────────────────────┘                  
  │                                           
  └ 1. read your drizzle schema
    2. generated SQL representation of your schema
  ┌ 3. outputs to console
  │    
  │        
  v
```
```sql
CREATE TABLE "users" (
 "id" SERIAL PRIMARY KEY,
 "name" TEXT,
 "email" TEXT UNIQUE
);
```
```
┌───────────────────────────────────┐                  
│ (._.) now you run your migrations │           
└─┬─────────────────────────────────┘  
  │
 via Atlas
  │                                    ┌──────────────┐
  │  ┌────────────────────┐            │              │
  └──│ Atlas              ├───────────>│  Database    │      
     └────────────────────┘            │              │       
                                       └──────────────┘

[✓] done!                                                 
```
</Section>
</Callout>

<rem/>
<rem/>


Source: https://orm.drizzle.team/docs/pg/operators

import Section from '@mdx/Section.astro';
import Callout from "@mdx/Callout.astro";

# Filter and conditional operators

<Callout type='info'>
All the values provided to filter operators and to the `sql` function are parameterized automatically.
For example, this query:
```ts
await db.select().from(users).where(eq(users.id, 42));
```
will be translated to:
```sql
select "id", "name", "age" from "users" where "users"."id" = $1; -- params: [42]
```
</Callout>

<br/>

We natively support all dialect specific filter and conditional operators.

You can import all filter & conditional from `drizzle-orm`:
```typescript copy
import { eq, ne, gt, gte, ... } from "drizzle-orm";
```

### eq

  
Value equal to `n`
<Section>
```typescript copy
import { eq } from "drizzle-orm";

db.select().from(table).where(eq(table.column, 5));
```

```sql copy
SELECT * FROM "table" WHERE "table"."column" = 5
```
</Section>

<Section>
```typescript
import { eq } from "drizzle-orm";

db.select().from(table).where(eq(table.column1, table.column2));
```

```sql
SELECT * FROM "table" WHERE "table"."column1" = "table"."column2"
```
</Section>

### ne

  
Value is not equal to `n`  
<Section>
```typescript
import { ne } from "drizzle-orm";

db.select().from(table).where(ne(table.column, 5));
```

```sql
SELECT * FROM "table" WHERE "table"."column" <> 5
```
</Section>

<Section>
```typescript
import { ne } from "drizzle-orm";

db.select().from(table).where(ne(table.column1, table.column2));
```

```sql
SELECT * FROM "table" WHERE "table"."column1" <> "table"."column2"
```
</Section>

## ---

### gt
 
  
Value is greater than `n`
<Section>
```typescript
import { gt } from "drizzle-orm";

db.select().from(table).where(gt(table.column, 5));
```

```sql
SELECT * FROM "table" WHERE "table"."column" > 5
```
</Section>

<Section>
```typescript
import { gt } from "drizzle-orm";

db.select().from(table).where(gt(table.column1, table.column2));
```

```sql
SELECT * FROM "table" WHERE "table"."column1" > "table"."column2"
```
</Section>

### gte

  
Value is greater than or equal to `n`
<Section>
```typescript
import { gte } from "drizzle-orm";

db.select().from(table).where(gte(table.column, 5));
```

```sql
SELECT * FROM "table" WHERE "table"."column" >= 5
```
</Section>

<Section>
```typescript
import { gte } from "drizzle-orm";

db.select().from(table).where(gte(table.column1, table.column2));
```

```sql
SELECT * FROM "table" WHERE "table"."column1" >= "table"."column2"
```
</Section>

### lt

  
Value is less than `n`
<Section>
```typescript
import { lt } from "drizzle-orm";

db.select().from(table).where(lt(table.column, 5));
```

```sql
SELECT * FROM "table" WHERE "table"."column" < 5
```
</Section>

<Section>
```typescript
import { lt } from "drizzle-orm";

db.select().from(table).where(lt(table.column1, table.column2));
```

```sql
SELECT * FROM "table" WHERE "table"."column1" < "table"."column2"
```
</Section>

### lte

  
Value is less than or equal to `n`.

<Section>
```typescript
import { lte } from "drizzle-orm";

db.select().from(table).where(lte(table.column, 5));
```

```sql
SELECT * FROM "table" WHERE "table"."column" <= 5
```
</Section>

<Section>
```typescript
import { lte } from "drizzle-orm";

db.select().from(table).where(lte(table.column1, table.column2));
```

```sql
SELECT * FROM "table" WHERE "table"."column1" <= "table"."column2"
```
</Section>

## ---

### exists

  
Value exists
<Section>
```typescript
import { exists } from "drizzle-orm";

const query = db.select().from(table2)
db.select().from(table).where(exists(query));
```

```sql
SELECT * FROM "table" WHERE EXISTS (SELECT * FROM "table2")
```
</Section>

### notExists

<Section>
```typescript
import { notExists } from "drizzle-orm";

const query = db.select().from(table2)
db.select().from(table).where(notExists(query));
```

```sql
SELECT * FROM "table" WHERE NOT EXISTS (SELECT * FROM "table2")
```
</Section>

### isNull
  
Value is `null`
<Section>
```typescript
import { isNull } from "drizzle-orm";

db.select().from(table).where(isNull(table.column));
```

```sql
SELECT * FROM "table" WHERE ("table"."column" IS NULL)
```
</Section>

### isNotNull

  
Value is not `null`
<Section>
```typescript
import { isNotNull } from "drizzle-orm";

db.select().from(table).where(isNotNull(table.column));
```

```sql
SELECT * FROM "table" WHERE ("table"."column" IS NOT NULL)
```
</Section>

## ---

### inArray

  
Value is in array of values
<Section>
```typescript
import { inArray } from "drizzle-orm";

db.select().from(table).where(inArray(table.column, [1, 2, 3, 4]));
```

```sql
SELECT * FROM "table" WHERE "table"."column" IN (1, 2, 3, 4)
```
</Section>

<Section>
```typescript
import { inArray } from "drizzle-orm";

const query = db.select({ data: table2.column }).from(table2);
db.select().from(table).where(inArray(table.column, query));
```

```sql
SELECT * FROM "table" WHERE "table"."column" IN (SELECT "table2"."column" FROM "table2")
```
</Section>

### notInArray

  
Value is not in array of values
<Section>
```typescript
import { notInArray } from "drizzle-orm";

db.select().from(table).where(notInArray(table.column, [1, 2, 3, 4]));
```

```sql
SELECT * FROM "table" WHERE "table"."column" NOT IN (1, 2, 3, 4)
```
</Section>

<Section>
```typescript
import { notInArray } from "drizzle-orm";

const query = db.select({ data: table2.column }).from(table2);
db.select().from(table).where(notInArray(table.column, query));
```

```sql
SELECT * FROM "table" WHERE "table"."column" NOT IN (SELECT "table2"."column" FROM "table2")
```
</Section>

## ---

### between

  
Value is between two values
<Section>
```typescript
import { between } from "drizzle-orm";

db.select().from(table).where(between(table.column, 2, 7));
```

```sql
SELECT * FROM "table" WHERE "table"."column" BETWEEN 2 AND 7
```
</Section>

### notBetween

  
Value is not between two value
<Section>
```typescript
import { notBetween } from "drizzle-orm";

db.select().from(table).where(notBetween(table.column, 2, 7));
```

```sql
SELECT * FROM "table" WHERE "table"."column" NOT BETWEEN 2 AND 7
```
</Section>

## ---

### like

  
Value is like other value, case sensitive
<Section>
```typescript
import { like } from "drizzle-orm";

db.select().from(table).where(like(table.column, "%llo wor%"));
```

```sql
SELECT * FROM "table" WHERE "table"."column" LIKE '%llo wor%'
```
</Section>

### notLike

  
Value is not like other value, case sensitive
<Section>
```typescript
import { notLike } from "drizzle-orm";

db.select().from(table).where(notLike(table.column, "%llo wor%"));
```

```sql
SELECT * FROM "table" WHERE "table"."column" NOT LIKE '%llo wor%'
```
</Section>

### ilike

  
Value is like some other value, case insensitive
<Section>
```typescript
import { ilike } from "drizzle-orm";

db.select().from(table).where(ilike(table.column, "%llo wor%"));
```

```sql
SELECT * FROM "table" WHERE "table"."column" ILIKE '%llo wor%'
```
</Section>

### notIlike

  
Value is not like some other value, case insensitive
<Section>
```typescript
import { notIlike } from "drizzle-orm";

db.select().from(table).where(notIlike(table.column, "%llo wor%"));
```

```sql
SELECT * FROM "table" WHERE "table"."column" NOT ILIKE '%llo wor%'
```
</Section>

## ---

### not

  
All conditions must return `false`.

<Section>
```typescript
import { eq, not } from "drizzle-orm";

db.select().from(table).where(not(eq(table.column, 5)));
```

```sql
SELECT * FROM "table" WHERE NOT ("table"."column" = 5)
```
</Section>

### and

  
All conditions must return `true`.

<Section>
```typescript
import { gt, lt, and } from "drizzle-orm";

db.select().from(table).where(and(gt(table.column, 5), lt(table.column, 7)));
```

```sql
SELECT * FROM "table" WHERE ("table"."column" > 5 AND "table"."column" < 7)
```
</Section>

### or

  
One or more conditions must return `true`.

<Section>
```typescript
import { gt, lt, or } from "drizzle-orm";

db.select().from(table).where(or(gt(table.column, 5), lt(table.column, 7)));
```

```sql
SELECT * FROM "table" WHERE ("table"."column" > 5 OR "table"."column" < 7)
```
</Section>

## ---

### arrayContains

  
Test that a column or expression contains all elements of the list passed as the second argument

<Section>
```typescript
import { arrayContains } from "drizzle-orm";

const contains = await db.select({ id: posts.id }).from(posts)
  .where(arrayContains(posts.tags, ['Typescript', 'ORM']));

const withSubQuery = await db.select({ id: posts.id }).from(posts)
  .where(arrayContains(
    posts.tags,
    db.select({ tags: posts.tags }).from(posts).where(eq(posts.id, 1)),
  ));
```

```sql
select "id" from "posts" where "posts"."tags" @> {Typescript,ORM};
select "id" from "posts" where "posts"."tags" @> (select "tags" from "posts" where "posts"."id" = 1);
```
</Section>

### arrayContained

  
Test that the list passed as the second argument contains all elements of a column or expression

<Section>
```typescript
import { arrayContained } from "drizzle-orm";

const contained = await db.select({ id: posts.id }).from(posts)
  .where(arrayContained(posts.tags, ['Typescript', 'ORM']));
```

```sql
select "id" from "posts" where "posts"."tags" <@ {Typescript,ORM};
```
</Section>

### arrayOverlaps

  
Test that a column or expression contains any elements of the list passed as the second argument.

<Section>
```typescript
import { arrayOverlaps } from "drizzle-orm";

const overlaps = await db.select({ id: posts.id }).from(posts)
  .where(arrayOverlaps(posts.tags, ['Typescript', 'ORM']));
```

```sql
select "id" from "posts" where "posts"."tags" && {Typescript,ORM}
```
</Section>


Source: https://orm.drizzle.team/docs/pg/overview

import Callout from '@mdx/Callout.astro';
import CodeTabs from '@mdx/CodeTabs.astro';
import YoutubeCards from '@mdx/YoutubeCards.astro';
import GetStartedLinks from '@mdx/GetStartedLinks/index.astro'

# Drizzle ORM

Drizzle ORM is a headless TypeScript ORM with a head. 🐲
> Drizzle is a good friend who's there for you when necessary and doesn't bother when you need some space.

It looks and feels simple, performs on day _1000_ of your project,\
lets you do things your way, and is there when you need it.

**It's the only ORM with both [relational](/docs/rqb) and [SQL-like](/docs/select) query APIs**, 
providing you the best of both worlds when it comes to accessing your relational data. 
Drizzle is lightweight, performant, typesafe, non-lactose, gluten-free, sober, flexible and **serverless-ready by design**.
Drizzle is not just a library, it's an experience. 🤩

[![Drizzle bestofjs](@/assets/images/bestofjs.jpg)](https://bestofjs.org/projects/drizzle-orm)

## Headless ORM? 
First and foremost, Drizzle is a library and a collection of complementary opt-in tools. 

**ORM** stands for _object relational mapping_, and developers tend to call Django-like or Spring-like tools an ORM. 
We truly believe it's a misconception based on legacy nomenclature, and we call them **data frameworks**.

<Callout type="error" emoji="️💔">
  With data frameworks you have to build projects **around them** and not **with them**.
</Callout>

**Drizzle** lets you build your project the way you want, without interfering with your project or structure. 

Using Drizzle you can define and manage database schemas in TypeScript, access your data in a SQL-like 
or relational way, and take advantage of opt-in tools 
to push your developer experience _through the roof_. 🤯 

## Why SQL-like?
**If you know SQL, you know Drizzle.**

Other ORMs and data frameworks tend to deviate/abstract you away from SQL, which 
leads to a double learning curve: needing to know both SQL and the framework's API.  

Drizzle is the opposite. 
We embrace SQL and built Drizzle to be SQL-like at its core, so you can have zero to no 
learning curve and access to the full power of SQL.  

We bring all the familiar **[SQL schema](/docs/sql-schema-declaration)**, **[queries](/docs/select)**, 
**[automatic migrations](/docs/migrations)** and **[one more thing](/docs/rqb)**. ✨

<CodeTabs items={["index.ts", "schema.ts", "migration.sql"]}>
```typescript copy
// Access your data
await db
	.select()
	.from(countries)
	.leftJoin(cities, eq(cities.countryId, countries.id))
	.where(eq(countries.id, 10))
```
```typescript copy
// manage your schema
export const countries = pgTable('countries', {
  id: serial().primaryKey(),
  name: varchar({ length: 256 }),
});

export const cities = pgTable('cities', {
  id: serial().primaryKey(),
  name: varchar({ length: 256 }),
  countryId: integer('country_id').references(() => countries.id),
});
```
```sql
CREATE TABLE "countries" (
	"id" serial PRIMARY KEY,
	"name" varchar(256)
);

CREATE TABLE "cities" (
	"id" serial PRIMARY KEY,
	"name" varchar(256),
	"country_id" integer
);

ALTER TABLE "cities" ADD CONSTRAINT "cities_country_id_countries_id_fkey" FOREIGN KEY ("country_id") REFERENCES "countries"("id");
```
</CodeTabs>

## Why not SQL-like?
We're always striving for a perfectly balanced solution, and while SQL-like does cover 100% of the needs, 
there are certain common scenarios where you can query data in a better way.  

We've built the **[Queries API](/docs/rqb)** for you, so you can fetch relational nested data from the database 
in the most convenient and performant way, and never think about joins and data mapping.  

**Drizzle always outputs exactly 1 SQL query.** Feel free to use it with serverless databases and never worry about performance or roundtrip costs!

```ts
const result = await db.query.users.findMany({
	with: {
		posts: true
	},
});
```

## Serverless?
<Callout type="info" emoji="🥳">
  The best part is no part. **Drizzle has exactly 0 dependencies!**
</Callout>


![Drizzle is slim an Serverless ready](@/assets/images/drizzle31kb.jpg)
  
Drizzle ORM is dialect-specific, slim, performant and serverless-ready **by design**.  

We've spent a lot of time to make sure you have best-in-class SQL dialect support, including Postgres, MySQL, and others.

Drizzle operates natively through industry-standard database drivers. We support all major **[PostgreSQL](/docs/get-started-postgresql)**, **[MySQL](/docs/mysql/get-started-mysql)**, **[SQLite](/docs/sqlite/get-started-sqlite)**, **[SingleStore](/docs/singlestore/get-started-singlestore)**, **[MSSQL](/docs/mssql/get-started-mssql)** or **[CockroachDB](/docs/cockroach/get-started-cockroach)** drivers out there, and we're adding new ones **[really fast](https://twitter.com/DrizzleORM/status/1653082492742647811?s=20)**.  


## Welcome on board!
More and more companies are adopting Drizzle in production, experiencing immense benefits in both DX and performance.

**We're always there to help, so don't hesitate to reach out. We'll gladly assist you in your Drizzle journey!**

We have an outstanding **[Discord community](https://driz.link/discord)** and welcome all builders to our **[Twitter](https://twitter.com/drizzleorm)**.
  
Now go build something awesome with Drizzle and your **[PostgreSQL](/docs/get-started-postgresql)**, **[MySQL](/docs/mysql/get-started-mysql)**, **[SQLite](/docs/sqlite/get-started-sqlite)**, **[MSSQL](/docs/mssql/get-started-mssql)** or **[CockroachDB](/docs/cockroach/get-started-cockroach)** database. 🚀

### Video Showcase

{/* tRPC + NextJS App Router = Simple Typesafe APIs
Jack Herrington 19:17
https://www.youtube.com/watch?v=qCLV0Iaq9zU */}
{/* https://www.youtube.com/watch?v=qDunJ0wVIec */}
{/* https://www.youtube.com/watch?v=NZpPMlSAez0 */}

 {/* https://www.youtube.com/watch?v=-A0kMiJqQRY */}

<YoutubeCards cards={[
	{
		id: "vyU5mJGCJMw",
		title: "Full Drizzle Course for Beginners",
		description: "Code Genix",
		time: "1:37:39",
	},
	{
		id: "7-NZ0MlPpJA",
		title: "Learn Drizzle In 60 Minutes",
		description: "Web Dev Simplified",
		time: "56:09"
	},
	{
		id: "i_mAHOhpBSA",
		title: "Drizzle ORM in 100 Seconds",
		description: "Fireship",
		time: "2:55"
	},
	{
		id: "hIYNOiZXQ7Y",
		title: "Learn Drizzle ORM in 13 mins (crash course)",
		description: "Neon",
		time: "14:00"
	},
	{
		id: "4ZhtoOFKFP8",
		title: "Easiest Database Setup in Next.js&nbsp;14 with Turso&nbsp;&&nbsp;Drizzle",
		description: "Sam Meech-Ward",
		time: '38:08'
	}, 
	{
		id: "NfVELsEZFsA",
		title: "Next.js Project with Vercel, Neon, Drizzle, TailwindCSS, FlowBite and more!",
		description: "CodingEntrepreneurs",
		time: '5:46:28'
	}, 
	{
		id: "_SLxGYzv6jo",
		title: "I Have A New Favorite Database&nbsp;Tool",
		description: "Theo - t3.gg",
		time: '5:46'
	}, 
	{
		id: "Qo-RXkSwOtc",
		title: "Drizzle ORM First impressions - migrations, relations, queries!",
		description: "Marius Espejo",
		time: '33:52'
	},
	{
		id: "yXNEqyvA0OY",
		title: "I want to learn Drizzle ORM, so I'm starting another next14 project",
		description: "Web Dev Cody",
		time: "9:00"
	},
	{
		id: "h7vVhR-dFYo",
		title: "Picking an ORM is Getting Harder...",
		description: "Ben Davis",
		time: "5:18"
	},
	{
		id: "8met6WTk0mQ",
		title: "This New Database Tool is a Game-Changer",
		description: "Josh tried coding",
		time: "8:49"
	},
	{
		id: "woWW1T9DXEY",
		title: "My Favorite Database Tool Just Got EVEN Better",
		description: "Josh tried coding",
		time: "4:23"
	},
	{
		id: "A3l6YYkXzzg",
		title: "SaaS Notion Clone with Realtime cursors, Nextjs 13, Stripe, Drizzle ORM, Tailwind, Supabase, Sockets",
		description: "Web Prodigies",
		time: "11:41:46"
	},
	{
		id: "EQfaw5bDE1s",
		title: "SvelteKit + Drizzle Code Breakdown",
		description: "Ben Davis",
		time: "12:18"
	},
	{
		id: "b6VhN_HHDiQ",
		title: "Build a Multi-Tenanted, Role-Based Access Control System",
		description: "TomDoesTech",
		time: "2:01:29"
	},
	/*
	This video became private
	Uncomment (in other files too) it when it becomes public again
	{
		id: "3tl9XCiQErA",
		title: "The Prisma killer is finally here",
		description: "SST",
		time: "5:42"
	},
	*/
	{
		id: "VQFjyEa8vGE",
		title: "Learning Drizzle ORM and working on a next14 project",
		description: "Web Dev Cody",
		time: "1:07:41"
	},
	{
		id: "5G0upg4sxgE",
		title: "This Trick Makes My Favorite Database Tool Even Better",
		description: "Josh tried coding",
		time: "6:01"
	},
	{
		id: "-JnEuvPmt-Q",
		title: "Effortless Auth in Next.js 14: Use Auth.js & Drizzle ORM for Secure Login",
		description: "Sam Meech-Ward",
		time: "26:29"
	},
]} />


Source: https://orm.drizzle.team/docs/pg/perf-queries

# Query performance
When it comes to **Drizzle** — we're a thin TypeScript layer on top of SQL with 
almost 0 overhead and to make it actual 0, you can utilise our prepared statements API.
  
**When you run a query on the database, there are several things that happen:**
- all the configurations of the query builder got concatenated to the SQL string
- that string and params are sent to the database driver
- driver compiles SQL query to the binary SQL executable format and sends it to the database

With prepared statements you do SQL concatenation once on the Drizzle ORM side and then database 
driver is able to reuse precompiled binary SQL instead of parsing query all the time. 
It has extreme performance benefits on large SQL queries.  

## Prepared statement

	```typescript copy {3}
    const db = drizzle(...);

    const prepared = db.select().from(customers).prepare("statement_name");
    
    const res1 = await prepared.execute();
    const res2 = await prepared.execute();
    const res3 = await prepared.execute();
    ```

## Placeholder
Whenever you need to embed a dynamic runtime value - you can use the `sql.placeholder(...)` api

```ts {6,9-10,15,18}
    import { sql } from "drizzle-orm";

    const p1 = db
      .select()
      .from(customers)
      .where(eq(customers.id, sql.placeholder('id')))
      .prepare("p1")

    await p1.execute({ id: 10 }) // SELECT * FROM customers WHERE id = 10
    await p1.execute({ id: 12 }) // SELECT * FROM customers WHERE id = 12

    const p2 = db
      .select()
      .from(customers)
      .where(sql`lower(${customers.name}) like ${sql.placeholder('name')}`)
      .prepare("p2");

    await p2.execute({ name: '%an%' }) // SELECT * FROM customers WHERE lower(name) like '%an%'
    ```


Source: https://orm.drizzle.team/docs/pg/query-utils

import $count from '@mdx/$count-pg.mdx';

# Drizzle query utils

### $count
<$count/>

Source: https://orm.drizzle.team/docs/pg/read-replicas

# Read Replicas

When your project involves a set of read replica instances, and you require a convenient method for managing 
SELECT queries from read replicas, as well as performing create, delete, and update operations on the primary 
instance, you can leverage the `withReplicas()` function within Drizzle

```ts copy
import { sql } from 'drizzle-orm';
import { drizzle } from 'drizzle-orm/node-postgres';
import { boolean, jsonb, pgTable, serial, text, timestamp, withReplicas } from 'drizzle-orm/pg-core';

const usersTable = pgTable("users", {
  id: serial().primaryKey(),
  name: text().notNull(),
  verified: boolean().notNull().default(false),
  jsonb: jsonb().$type<string[]>(),
  createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
});

const primaryDb = drizzle("postgres://user:password@host:port/primary_db");
const read1 = drizzle("postgres://user:password@host:port/read_replica_1");
const read2 = drizzle("postgres://user:password@host:port/read_replica_2");

const db = withReplicas(primaryDb, [read1, read2]);
```

You can now use the `db` instance the same way you did before. Drizzle will 
handle the choice between read replica and the primary instance automatically

```ts
// Read from either the read1 connection or the read2 connection
await db.select().from(usersTable)

// Use the primary database for the delete operation
await db.delete(usersTable).where(eq(usersTable.id, 1))
```

You can use the `$primary` key to force using primary instances even for read operations

```ts
// read from primary
await db.$primary.select().from(usersTable);
```

With Drizzle, you can also specify custom logic for choosing read replicas. 
You can make a weighted decision or any other custom selection method for random read replica choice. 
Here is an 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 selected.

Keep in mind that you can implement any type of random selection method 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]!
});

await db.select().from(usersTable)
```


Source: https://orm.drizzle.team/docs/pg/relations-schema-declaration

import Tab from '@mdx/Tab.astro';
import Tabs from '@mdx/Tabs.astro';
import Callout from '@mdx/Callout.astro';
import SimpleLinkCards from '@mdx/SimpleLinkCards.astro';
import CodeTabs from "@mdx/CodeTabs.astro";
import Section from '@mdx/Section.astro';
import Flex from "@mdx/Flex.astro"
import LinksList from "@mdx/LinksList.astro"

# Drizzle Relations Fundamentals

In the world of databases, especially relational databases, the concept of relations is absolutely fundamental.
Think of "relations" as the connections and links between different pieces of data. Just like in real life, 
where people have relationships with each other, or objects are related to categories, databases use relations to model how different 
types of information are connected and work together.

### Normalization
Normalization is the process of organizing data in your database to reduce redundancy (duplication) and improve data integrity 
(accuracy and consistency). Think of it like tidying up a messy filing cabinet. Instead of having all sorts of papers 
crammed into one folder, you organize them into logical folders and categories to make everything easier to find and manage.

<Callout collapsed="Why is Normalization Important?">
- **Reduces Data Redundancy**: Imagine storing a customer's address every time they place an order. If the address changes, you'd have to update it in multiple places! Normalization helps you store information in one place and refer to it from other places, minimizing repetition.
- **Improves Data Integrity**: Less redundancy means less chance of inconsistencies. If you update an address in one place, it's updated everywhere it's needed.
- **Prevents Anomalies**: Normalization helps prevent issues like:
  1. **Insertion Anomalies**: Difficulty adding new data because you're missing related information.
  2. **Update Anomalies**: Having to update the same information in multiple rows.
  3. **Deletion Anomalies**: Accidentally losing valuable information when you delete something seemingly unrelated.
- **Easier to Understand and Maintain**: A normalized database is generally more logically structured and easier to understand, query, and modify.
</Callout>

Normalization is often described in terms of "normal forms" (1NF, 2NF, 3NF, and beyond). While the details can get quite technical, the core ideas are straightforward:

#### 1NF (First Normal Form): `Atomic Values`

**Goal**: Each column should hold a single, indivisible value. No repeating groups of data within a single cell

**Example**: Instead of having a single `address` column that stores `123 Main St, City, USA`, you'd 
break it down into separate columns: `street_address`, `city`, `state`, `zip_code`.

```sql
-- Unnormalized (violates 1NF)
CREATE TABLE "Customers_Unnormalized" (
    "customer_id" INTEGER PRIMARY KEY,
    "name" VARCHAR(255),
    "address" VARCHAR(255) -- Problem: Multiple pieces of info in one column
);

-- Normalized to 1NF
CREATE TABLE "Customers_1NF" (
    "customer_id" INTEGER PRIMARY KEY,
    "name" VARCHAR(255),
    "street_address" VARCHAR(255),
    "city" VARCHAR(255),
    "state" VARCHAR(255),
    "zip_code" VARCHAR(10)
);
```

#### 2NF (Second Normal Form): `Eliminate Redundant Data Dependent on Part of the Key`

**Goal**: Applies when you have a table with a composite primary key (a primary key made up of two or more columns). 
2NF ensures that all non-key attributes are fully dependent on the entire composite primary key, not just part of it.

Imagine we have a table called `order_items`. This table tracks items within orders, and we use a composite primary key (`order_id`, `product_id`) 
because a single order can have multiple of the same product (though in this simplified example, let's assume each product appears only 
once per order for clarity, but the composite key logic still applies).

<Callout collapsed="Expand for visual example">
```sql
CREATE TABLE "OrderItems_Unnormalized" (
    "order_id" INTEGER,
    "product_id" VARCHAR(10),
    "product_name" VARCHAR(100),
    "product_price" DECIMAL(10, 2),
    "quantity" INTEGER,
    "order_date" DATE,
    PRIMARY KEY ("order_id", "product_id") -- Composite Primary Key
);

INSERT INTO "OrderItems_Unnormalized" ("order_id", "product_id", "product_name", "product_price", "quantity", "order_date") VALUES
(101, 'A123', 'Laptop', 1200.00, 1, '2023-10-27'),
(101, 'B456', 'Mouse', 25.00, 2, '2023-10-27'),
(102, 'A123', 'Laptop', 1200.00, 1, '2023-10-28'),
(103, 'C789', 'Keyboard', 75.00, 1, '2023-10-29');
```
```
+------------------------------------------------------------------------------------+
| OrderItems_Unnormalized                                                            |
+------------------------------------------------------------------------------------+
| PK (order_id, product_id) | product_name | product_price | quantity | order_date   |
+------------------------------------------------------------------------------------+
| 101, A123               | Laptop       | 1200.00       | 1        | 2023-10-27     |
| 101, B456               | Mouse        | 25.00         | 2        | 2023-10-27     |
| 102, A123               | Laptop       | 1200.00       | 1        | 2023-10-28     |
| 103, C789               | Keyboard     | 75.00         | 1        | 2023-10-29     |
+------------------------------------------------------------------------------------+
```
</Callout>

**Problem**: Notice that `product_name` and `product_price` are repeated whenever the same `product_id` appears in different orders. 
These attributes are only dependent on `product_id`, which is part of the composite primary key (`order_id`, `product_id`), but not the entire key. 
This is a partial dependency.

To achieve 2NF, we need to remove the partially dependent attributes (`product_name`, `product_price`) and place them in a separate table where they are 
fully dependent on the primary key of that new table.

<Callout collapsed="Normalization to 2NF: Visual explanation">
```
+-------------------+     1:M     +---------------------------+
| Products          | <---------- | OrderItems_2NF            |
+-------------------+             +---------------------------+
| PK product_id     |             | PK (order_id, product_id) |
| product_name      |             | quantity                  |
| product_price     |             | order_date                |
+-------------------+             | FK product_id             |
                                  +---------------------------+
```
```sql
CREATE TABLE "Products" (
    "product_id" VARCHAR(10) PRIMARY KEY,
    "product_name" VARCHAR(100),
    "product_price" DECIMAL(10, 2)
);

CREATE TABLE "OrderItems_2NF" (
    "order_id" INTEGER,
    "product_id" VARCHAR(10),
    "quantity" INTEGER,
    "order_date" DATE,
    PRIMARY KEY ("order_id", "product_id"), -- Composite Primary Key remains
    FOREIGN KEY ("product_id") REFERENCES "Products"("product_id") -- Foreign Key to Products
);

-- Insert data into Products
INSERT INTO "Products" ("product_id", "product_name", "product_price") VALUES
('A123', 'Laptop', 1200.00),
('B456', 'Mouse', 25.00),
('C789', 'Keyboard', 75.00);

-- Insert data into OrderItems_2NF (referencing Products)
INSERT INTO "OrderItems_2NF" ("order_id", "product_id", "quantity", "order_date") VALUES
(101, 'A123', 1, '2023-10-27'),
(101, 'B456', 2, '2023-10-27'),
(102, 'A123', 1, '2023-10-28'),
(103, 'C789', 1, '2023-10-29');
```
</Callout>

#### 3NF (Third Normal Form): `Eliminate Redundant Data Dependent on Non-Key Attributes`

**Goal**: Remove data that is dependent on other non-key attributes. This is about eliminating transitive dependencies.

**Problem**: Let's say we have a `suppliers` table. We store supplier information, including their `zip_code`, `city`, and `state`. `supplier_id` is the primary key.

<Callout collapsed="">
```sql
CREATE TABLE "suppliers" (
    "supplier_id" VARCHAR(10) PRIMARY KEY,
    "supplier_name" VARCHAR(255),
    "zip_code" VARCHAR(10),
    "city" VARCHAR(100),
    "state" VARCHAR(50)
);

INSERT INTO "suppliers" ("supplier_id", "supplier_name", "zip_code", "city", "state") VALUES
('S1', 'Acme Corp', '12345', 'Anytown', 'NY'),
('S2', 'Beta Inc', '67890', 'Otherville', 'CA'),
('S3', 'Gamma Ltd', '12345', 'Anytown', 'NY');
```
```
+---------------------------------------------------------------+
| suppliers                                                     |
+---------------------------------------------------------------+
| PK supplier_id | supplier_name | zip_code | city      | state |
+---------------------------------------------------------------+
| S1             | Acme Corp     | 12345    | Anytown    | NY   |
| S2             | Beta Inc      | 67890    | Otherville | CA   |
| S3             | Gamma Ltd     | 12345    | Anytown    | NY   |
+---------------------------------------------------------------+
```
</Callout>

**Solution**: To achieve 3NF, we remove the attributes dependent on the non-key attribute (`city`, `state` dependent on `zip_code`) and put 
them into a separate table keyed by the non-key attribute itself (`zip_code`).

<Callout collapsed="Normalization to 3NF: Visual explanation">
```
+-------------------+     1:M     +--------------------+
| zip_codes         | <---------- | suppliers          |
+-------------------+             +--------------------+
| PK zip_code       |             | PK supplier_id     |
| city              |             | supplier_name      |
| state             |             | FK zip_code        |
+-------------------+             +--------------------+
```
```sql
CREATE TABLE "zip_codes" (
    "zip_code" VARCHAR(10) PRIMARY KEY,
    "city" VARCHAR(100),
    "state" VARCHAR(50)
);

CREATE TABLE "suppliers" (
    "supplier_id" VARCHAR(10) PRIMARY KEY,
    "supplier_name" VARCHAR(255),
    "zip_code" VARCHAR(10), -- Foreign Key to zip_codes
    FOREIGN KEY ("zip_code") REFERENCES "zip_codes"("zip_code")
);

-- Insert data into zip_codes
INSERT INTO "zip_codes" ("zip_code", "city", "state") VALUES
('12345', 'Anytown', 'NY'),
('67890', 'Otherville', 'CA');

-- Insert data into suppliers (referencing zip_codes)
INSERT INTO "suppliers" ("supplier_id", "supplier_name", "zip_code") VALUES
('S1', 'Acme Corp', '12345'),
('S2', 'Beta Inc', '67890'),
('S3', 'Gamma Ltd', '12345');
```
</Callout>

<Callout title="Good to know">
There are additional normal forms, such as `4NF`, `5NF`, `6NF`, `EKNF`, `ETNF`, and `DKNF`. We won't cover these here, but we will create a 
dedicated set of tutorials for them in our guides and tutorials section.
</Callout>

### Database Relationships
#### One-to-One

In a one-to-one relationship, each record in `table A` is related to at most one record in `table B`, and each record in `table B` is
related to at most one record in `table A`. It's a very direct, exclusive pairing.

<Callout collapsed="Use Cases & Examples">
1. **User Profiles and User Account Details**: Think of a website. Each user account (in a Users table) might have exactly one user profile (in a UserProfiles table) containing more detailed information.
2. **Employees and Parking Spaces**: An Employees table and a ParkingSpaces table. Each employee might be assigned at most one parking space, and each parking space is assigned to at most one employee.
3. **Splitting Tables for Organization**: Sometimes, you might split a very wide table into two for better organization or security reasons, maintaining a 1-1 relationship between them.

```
Table A (One Side)      Table B (One Side)
+---------+             +---------+
| PK (A)  | <---------> | FK (A)  | (Foreign Key referencing Table A)
| ...     |             | ...     |
+---------+             +---------+
```
</Callout>


#### One-to-Many

In a one-to-many relationship, one record in `table A` can be related to many records in `table B`, but each 
record in `table B` is related to at most one record in `table A`. Think of it as a "parent-child" relationship.

<Callout collapsed="Use Cases & Examples">
1. **Customers and Orders**: One customer can place many orders, but each order belongs to only one customer.
2. **Authors and Books**: One author can write many books, but (let's simplify for now and say) each book is written by one primary author.
3. **Departments and Employees**: One department can have many employees, but each employee belongs to only one department.

```
Table A (One Side)      Table B (Many Side)
+---------+             +---------+
| PK (A)  | ----------> | FK (A)  | (Foreign Key referencing Table A)
| ...     |             | ...     |
+---------+             +---------+
     (One)                  (Many)
```
</Callout>

#### Many-to-Many

In a many-to-many relationship, one record in `table A` can be related to many records in `table B`, and one 
record in `table B` can be related to many records in `table A`. It's a more complex, bidirectional relationship.

<Callout collapsed="Use Cases & Examples">
1. **Students and Courses**: One student can enroll in many courses, and one course can have many students enrolled.
2. **Products and Categories**: One product can belong to multiple categories (e.g., a "T-shirt" can be
in "Clothing" and "Summer Wear" categories), and one category can contain many products.
3. **Authors and Books**: A book can be written by multiple authors, and an author can write multiple books.

```
Table A (Many Side)    Junction Table      Table B (Many Side)
+---------+          +-------------+     +---------+
| PK (A)  | -------->| FK (A)      | <----| FK (B)  |
| ...     |          | FK (B)      |     | ...     |
+---------+          +-------------+     +---------+
     (Many)             (Junction)          (Many)
```
</Callout>

Many-to-many relationships are not directly implemented with foreign keys between the two main tables. 
Instead, you need a `junction` table (also called an associative table or bridging table). 
This table acts as an intermediary to link records from both tables.

```sql
-- Table for Students (Many side)
CREATE TABLE "students" (
    "id" INTEGER PRIMARY KEY,
    "name" VARCHAR(255)
);

-- Table for Courses (Many side)
CREATE TABLE "courses" (
    "id" INTEGER PRIMARY KEY,
    "name" VARCHAR(255),
    "credits" INTEGER
);

-- Junction Table: Enrollments (Connects Students and Courses - M-M relationship)
CREATE TABLE "enrollments" (
    "id" INTEGER GENERATED ALWAYS AS IDENTITY PRIMARY KEY, -- Optional, but good practice for junction tables
    "student_id" INTEGER,
    "course_id" INTEGER,
    "enrollment_date" DATE,
    -- Composite Foreign Keys (often part of a composite primary key or unique constraint)
    FOREIGN KEY ("student_id") REFERENCES "students"("id"),
    FOREIGN KEY ("course_id") REFERENCES "courses"("id"),
    UNIQUE ("student_id", "course_id") -- Prevent duplicate enrollments for the same student and course
);
```

### Why Foreign Keys?

You might think of foreign key constraints as simply a way to validate data - ensuring 
that when you enter a value in a foreign key column, that value actually exists in the primary key 
column of another table. And you'd be partially right! This value checking is the mechanism foreign keys use.

But it's crucial to understand that this validation is not the end goal, it's the means 
to a much larger purpose. Foreign key constraints are fundamentally about:

<Callout collapsed="1. Explicitly Defining and Enforcing Relationships">

We've discussed relationships like `One-to-Many` between Customers and Orders. 
A foreign key is the SQL language's way of telling the database: 

> Hey database, I want to enforce a 1-M relationship here. Every value in the customer_id column of the
Orders table must correspond to a valid customer_id in the Customers table.

It's not just a suggestion; it's a constraint the database actively enforces. 
The database becomes relationship-aware because of the foreign key.
</Callout>

<Callout collapsed="2. Maintaining Referential Integrity">
- This is the core of "data integrity" in the context of relationships. Referential integrity means 
that relationships between tables remain consistent and valid over time.
- Foreign keys prevent orphaned records. What's an orphaned record? In our Customer-Order example, 
an order that exists in the Orders table but doesn't have a corresponding customer in the Customers 
table would be an orphan. Foreign keys prevent this from happening (or control what happens 
if you try to delete a customer with orders - via CASCADE, SET NULL, etc.).
- Why is preventing orphans important? Orphaned records break the logical structure of your data. 
If you have an order without a customer, you lose crucial context. Queries become unreliable, reports
 become inaccurate, and your application's logic can break down.

**Example**:
```
Without a foreign key, you could accidentally delete a customer from the Customers 
table while their orders still exist in the Orders table. Suddenly, you have orders that point to 
a customer that no longer exists! A foreign key constraint prevents this data inconsistency.
```
</Callout>

<Callout collapsed="3. Facilitating Database Design and Understanding">
- Foreign keys are not just about technical enforcement; they are also a crucial part of database design documentation.
- When you see a foreign key in a database schema, it immediately tells you: 
`Table 'X' is related to Table 'Y' in this way.` It's a clear visual and structural indicator of relationships.
- This makes databases easier to understand, maintain, and evolve over time. New developers can quickly 
grasp how different parts of the database are connected.
</Callout>

In essence, foreign key constraints are not just about checking values; they are about:

1. Defining the rules of your data relationships
2. Actively enforcing those rules at the database level
3. Guaranteeing data integrity and consistency within those relationships
4. Making your database more robust, reliable, and understandable

### Why NOT Foreign Keys?

While highly beneficial, there are some scenarios where you might reconsider or use Foreign Keys with caution. 
These are typically edge cases and often involve trade-offs.

<Callout collapsed="1. Performance Overhead in Very High-Write Environments">
- **Scenario**: Extremely high-volume transactional systems (e.g., real-time logging, very high-frequency trading
platforms, massive IoT data ingestion).
- **Explanation**: Every time you insert or update data in a table with a foreign key, the database system 
needs to perform checks to ensure referential integrity. In extremely high-write scenarios, these 
checks can introduce a small but potentially noticeable performance overhead.
</Callout>

<Callout collapsed="2. Distributed Database Systems and Cross-Node Foreign Keys:">
- **Scenario**: Systems where data is distributed across multiple database nodes or clusters (common in sharded databases, cloud environments, and microservices).
- **Explanation**:  Cross-node foreign keys can introduce significant complexity and performance overhead. Validating referential integrity requires communication between nodes, leading to increased latency. Distributed transactions needed to maintain consistency are also more complex and can be less performant than local transactions. In such architectures, application-level data integrity checks or eventual consistency models might be considered alternatives.
</Callout>

<Callout collapsed="3. Legacy Systems and Data Integration with Non-Relational Data:">
- **Scenario**: Integrating a relational database with older legacy systems or non-relational data stores (e.g., NoSQL, flat files, external APIs).
- **Explanation**:  Legacy systems or non-relational data might not consistently adhere to the referential integrity rules enforced by foreign keys.  Imposing foreign keys in such scenarios can lead to data import issues, data inconsistencies, and might necessitate complex data transformation or application-level integrity management instead. You might need to carefully evaluate the data quality and consistency of the external sources and potentially rely on application logic or ETL processes to ensure data integrity instead of strictly enforcing foreign keys at the database level.
</Callout>

You can also check out some great explanations from the PlanetScale team in their [article](https://planetscale.com/docs/learn/operating-without-foreign-key-constraints#why-does-planetscale-not-recommend-constraints)

### Polymorphic Relations

Polymorphic relationships are a more advanced concept that allows a single relationship to point to 
different types of entities or tables. It's about creating more flexible and adaptable relationships when 
you have different kinds of data that share some commonality.

Imagine you have an `activities` log. An activity could be a `comment` a `like` or a `share`.
Each of these `activity` types has different details. Instead of creating separate tables and 
relationships for each activity type and the things they relate to, you might use a polymorphic approach.

<Callout collapsed="Common Scenarios & Examples">
- **Comments/Reviews**: A "Comment" might be related to different types of content: articles, products, videos, etc. 
Instead of having separate article_id, product_id, video_id columns in a Comments table, you can use a 
polymorphic relationship.
```
+---------------------+
| **Comments**        |
+---------------------+
| PK comment_id       |
| commentable_type    | ------>  [Polymorphic Relationship]
| commentable_id      | -------->
| user_id             |
| comment_text        |
| ...                 |
+---------------------+
          ^
          |
+---------------------+    +---------------------+    +---------------------+
| **Articles**        |    | **Products**        |    | **Videos**          |
+---------------------+    +---------------------+    +---------------------+
| PK article_id       |    | PK product_id       |    | PK video_id         |
| ...                 |    | ...                 |    | ...                 |
+---------------------+    +---------------------+    +---------------------+
```
- **Notifications:** A notification could be related to a user, an order, a system event, etc.
```
+----------------------+
| **Notifications**    |
+----------------------+
| PK notification_id  |
| notifiable_type     | ------>  [Polymorphic Relationship]
| notifiable_id       | -------->
| user_id             |
| message             |
| ...                  |
+----------------------+
           ^
           |
+---------------------+    +---------------------+    +-----------------------+
| **Users**           |    | **Orders**          |    | **System Events**     |
+---------------------+    +---------------------+    +-----------------------+
| PK user_id          |    | PK order_id         |    | PK event_id           |
| ...                 |    | ...                 |    | ...                   |
+---------------------+    +---------------------+    +-----------------------+
```
</Callout>

Polymorphic relationships are more complex and are often handled at the application level or 
using more advanced database features (depending on the specific database system). Standard SQL doesn't 
have direct, built-in support for enforcing polymorphic foreign key constraints in the same way as regular foreign keys.

Source: https://orm.drizzle.team/docs/pg/relations-v1-v2

import Callout from '@mdx/Callout.astro';
import Prerequisites from "@mdx/Prerequisites.astro";
import Section from '@mdx/Section.astro';
import Npx from "@mdx/Npx.astro";
import Npm from "@mdx/Npm.astro";
import CodeTabs from '@mdx/CodeTabs.astro';
import CodeTab from '@mdx/CodeTab.astro';

# Migrating to Relational Queries version 2

<Npm>
 drizzle-orm@rc
 drizzle-kit@rc -D
</Npm>

<br/>

<Prerequisites>
- **Relations Fundamentals** - [read here](/docs/relations-schema-declaration)
- **drizzle-kit pull** - [read here](/docs/drizzle-kit-pull)
</Prerequisites>

<Callout>
Below is the table of contents. Click an item to jump to that section:

- [What is working differently from v1](#what-is-working-differently-from-v1)  
- [New features in v2](#what-is-new)  
- [How to migrate relations definition from v1 to v2](#how-to-migrate-relations-schema-definition-from-v1-to)  
- [How to migrate queries from v1 to v2](#how-to-migrate-queries-from-v1-to-v2)  
- [Internal changes(imports, internal types, etc.)](#internal-changes)
</Callout>

### API changes
#### What is working differently from v1

{/* ##### Drizzle Relations schema definition */}

One of the biggest updates were in **Relations Schema definition**

The first difference is that you no longer need to specify `relations` for each table separately in different objects and
then pass them all to `drizzle()` along with your schema. In Relational Queries v2, you now have one dedicated place to
specify all the relations for all the tables you need.

The `r` parameter in the callback provides comprehensive autocomplete
functionality - including all tables from your schema and functions such as `one`, `many`, and `through` - essentially
offering everything you need to specify your relations.

```ts
// relations.ts
import * as schema from "./schema"
import { defineRelations } from "drizzle-orm"

export const relations = defineRelations(schema, (r) => ({
    ...
}));
```
```ts
// index.ts
import { relations } from "./relations"
import { drizzle } from "drizzle-orm/..."

const db = drizzle(process.env.DATABASE_URL, { relations })
```

##### What is different?

<Callout collapsed="Schema Definition">
```ts copy
import * as p from 'drizzle-orm/pg-core';

export const users = p.pgTable('users', {
	id: p.integer().primaryKey(),
	name: p.text(),
	invitedBy: p.integer('invited_by'),
});

export const posts = p.pgTable('posts', {
	id: p.integer().primaryKey(),
	content: p.text(),
	authorId: p.integer('author_id'),
});
```
</Callout>

**One place for all your relations**

<Callout title="❌ v1">
```ts
import { relations } from "drizzle-orm/_relations";
import { users, posts } from './schema';

export const usersRelation = relations(users, ({ one, many }) => ({
  invitee: one(users, {
    fields: [users.invitedBy],
    references: [users.id],
  }),
  posts: many(posts),
}));

export const postsRelation = relations(posts, ({ one, many }) => ({
  author: one(users, {
    fields: [posts.authorId],
    references: [users.id],
  }),
}));
```
</Callout>

<Callout title='✅ v2'>
```ts
import { defineRelations } from "drizzle-orm";
import * as schema from "./schema";

export const relations = defineRelations(schema, (r) => ({
  users: {
    invitee: r.one.users({
      from: r.users.invitedBy,
      to: r.users.id,
    }),
    posts: r.many.posts(),
  },
  posts: {
    author: r.one.users({
      from: r.posts.authorId,
      to: r.users.id,
    }),
  },
}));
```
</Callout>

You can still separate it into different `parts`, and you can make the parts any size you want

```ts
import { defineRelations, defineRelationsPart } from 'drizzle-orm';
import * as schema from "./schema";

export const relations = defineRelations(schema, (r) => ({
  users: {
    invitee: r.one.users({
      from: r.users.invitedBy,
      to: r.users.id,
    }),
    posts: r.many.posts(),
  }
}));

export const part = defineRelationsPart(schema, (r) => ({
  posts: {
    author: r.one.users({
      from: r.posts.authorId,
      to: r.users.id,
    }),
  }
}));
```

and then you can provide it to the db instance

```ts
const db = drizzle(process.env.DB_URL, { relations: { ...relations, ...part } })
```

**Define `many` without `one`**

In v1, if you wanted only the `many` side of a relationship, you had to specify the `one` side on the other end, 
which made for a poor developer experience.

In v2, you can simply use the `many` side without any additional steps

<Callout title="❌ v1">
```ts
import { relations } from "drizzle-orm/_relations";
import { users, posts } from './schema';

export const usersRelation = relations(users, ({ one, many }) => ({
  posts: many(posts),
}));

export const postsRelation = relations(posts, ({ one, many }) => ({
  author: one(users, {
    fields: [posts.authorId],
    references: [users.id],
  }),
}));
```
</Callout>

<Callout title='✅ v2'>
```ts
import { defineRelations } from "drizzle-orm";
import * as schema from "./schema";

export const relations = defineRelations(schema, (r) => ({
  users: {
    posts: r.many.posts({
      from: r.users.id,
      to: r.posts.authorId,
    }),
  },
}));
```
</Callout>

**New `optional` option**

`optional: false` at the type level makes the `author` key in the `posts` object required. 
This should be used when you are certain that this specific entity will always exist.

<Callout title="❌ v1">
Was not supported in v1
</Callout>

<Callout title='✅ v2'>
```ts {9}
import { defineRelations } from "drizzle-orm";
import * as schema from "./schema";

export const relations = defineRelations(schema, (r) => ({
  users: {
    posts: r.one.posts({
      from: r.users.id,
      to: r.posts.authorId,
      optional: false,
    }),
  },
}));
```
</Callout>

**No modes in `drizzle()`**

We found a way to use the same strategy for all MySQL dialects, so there's no need to specify them

<Callout title="❌ v1">
```ts
import * as schema from './schema'

const db = drizzle(process.env.DATABASE_URL, { mode: "planetscale", schema });
// or
const db = drizzle(process.env.DATABASE_URL, { mode: "default", schema });
```
</Callout>

<Callout title='✅ v2'>
```ts
import { relations } from './relations'

const db = drizzle(process.env.DATABASE_URL, { relations });
```
</Callout>

**`from` and `to` upgrades**

We've renamed `fields` to `from` and `references` to `to`, and we made both accept either a single value or an array

<Callout title="❌ v1">
```ts
...
author: one(users, {
  fields: [posts.authorId],
  references: [users.id],
}),
...
```
</Callout>

<Callout title='✅ v2'>
```ts
... 
author: r.one.users({
  from: r.posts.authorId,
  to: r.users.id,
}),
...
```
```ts
... 
author: r.one.users({
  from: [r.posts.authorId],
  to: [r.users.id],
}),
...
```
</Callout>

**`relationName` -> `alias`**

<Callout title="❌ v1">
```ts {8}
import { relations } from "drizzle-orm/_relations";
import { users, posts } from './schema';

export const postsRelation = relations(posts, ({ one }) => ({
  author: one(users, {
    fields: [posts.authorId],
    references: [users.id],
	  relationName: "author_post",
  }),
}));
```
</Callout>

<Callout title='✅ v2'>
```ts {9}
import { defineRelations } from "drizzle-orm";
import * as schema from "./schema";

export const relations = defineRelations(schema, (r) => ({
  posts: {
    author: r.one.users({
      from: r.posts.authorId,
      to: r.users.id,
      alias: "author_post",
    }),
  },
}));
```
</Callout>

**`custom types` new function**

There is a new [codec](/docs/codecs) function was added to custom types, so you can control how data is mapped

You can find out more [here](/docs/custom-types#ts-doc-for-type-definitions)

<Callout title='✅ v2'>
```ts
const customBytes = customType<{
  data: Buffer;
  driverData: Buffer;
  jsonData: string;
}>({
  dataType: () => "bytea",
  codec: "bytea",
});
```

</Callout>

##### What is new?

**`through` for many-to-many relations**

Previously, you would need to query through a junction table and then map it out for every response

You don't need to do it now!

<Callout collapsed='Schema'>
```ts
import * as p from "drizzle-orm/pg-core";

export const users = p.pgTable("users", {
  id: p.integer().primaryKey(),
  name: p.text(),
  verified: p.boolean().notNull(),
});

export const groups = p.pgTable("groups", {
  id: p.integer().primaryKey(),
  name: p.text(),
});

export const usersToGroups = p.pgTable(
  "users_to_groups",
  {
    userId: p
      .integer("user_id")
      .notNull()
      .references(() => users.id),
    groupId: p
      .integer("group_id")
      .notNull()
      .references(() => groups.id),
  },
  (t) => [p.primaryKey({ columns: [t.userId, t.groupId] })]
);
```
</Callout>

<Callout title="❌ v1">
```ts
export const usersRelations = relations(users, ({ many }) => ({
  usersToGroups: many(usersToGroups),
}));

export const groupsRelations = relations(groups, ({ many }) => ({
  usersToGroups: many(usersToGroups),
}));

export const usersToGroupsRelations = relations(usersToGroups, ({ one }) => ({
  group: one(groups, {
    fields: [usersToGroups.groupId],
    references: [groups.id],
  }),
  user: one(users, {
    fields: [usersToGroups.userId],
    references: [users.id],
  }),
}));
```
```ts
// Query example
const response = await db.query.users.findMany({
  with: {
    usersToGroups: {
      columns: {},
      with: {
        group: true,
      },
    },
  },
});
```
</Callout>

<Callout title='✅ v2'>
```ts
import * as schema from './schema';
import { defineRelations } from 'drizzle-orm';

export const relations = defineRelations(schema, (r) => ({
  users: {
    groups: r.many.groups({
      from: r.users.id.through(r.usersToGroups.userId),
      to: r.groups.id.through(r.usersToGroups.groupId),
    }),
  },
  groups: {
    participants: r.many.users(),
  },
}));
```
```ts
// Query example
const response = await db.query.users.findMany({
  with: {
    groups: true,
  },
});
```
</Callout>

**Predefined filters**

<Callout title="❌ v1">
Was not supported in v1
</Callout>

<Callout title='✅ v2'>
```ts {10-12}
import * as schema from './schema';
import { defineRelations } from 'drizzle-orm';

export const relations = defineRelations(schema,
  (r) => ({
    groups: {
      verifiedUsers: r.many.users({
        from: r.groups.id.through(r.usersToGroups.groupId),
        to: r.users.id.through(r.usersToGroups.userId),
        where: {
          verified: true,
        },
      }),
    },
  })
);
```
```ts {4}
// Query example: get groups with all verified users
const response = await db.query.groups.findMany({
  with: {
    verifiedUsers: true,
  },
});
```
</Callout>

##### `where` is now object

<Callout title="❌ v1">
```ts
const response = db._query.users.findMany({
  where: (users, { eq }) => eq(users.id, 1),
});
```
</Callout>

<Callout title="✅ v2">
```ts
const response = db.query.users.findMany({
  where: {
    id: 1,
  },
});
```

For a complete API Reference please check our [Select Filters docs](/docs/rqb#select-filters)
</Callout>

<Callout collapsed='Complex filter example using RAW'>
```ts
// schema.ts
import { integer, jsonb, pgTable, text, timestamp } from "drizzle-orm/pg-core";

export const users = pgTable("users", {
  id: integer().primaryKey(),
  name: text(),
  email: text().notNull(),
  age: integer(),
  createdAt: timestamp("created_at").defaultNow(),
  lastLogin: timestamp("last_login"),
  subscriptionEnd: timestamp("subscription_end"),
  lastActivity: timestamp("last_activity"),
  preferences: jsonb(),      // JSON column for user settings/preferences
  interests: text().array(),     // Array column for user interests
});
```
```ts
const response = await db.query.users.findMany({
  where: {
    AND: [
      {
        OR: [
          { RAW: (table) => sql`LOWER(${table.name}) LIKE 'john%'` },
          { name: { ilike: "jane%" } },
        ],
      },
      {
        OR: [
          { RAW: (table) => sql`${table.preferences}->>'theme' = 'dark'` },
          { RAW: (table) => sql`${table.preferences}->>'theme' IS NULL` },
        ],
      },
      { RAW: (table) => sql`${table.age} BETWEEN 25 AND 35` },
    ],
  },
});
```
</Callout>

##### `orderBy` is now object

<Callout title="❌ v1">
```ts
const response = db._query.users.findMany({
  orderBy: (users, { asc }) => [asc(users.id)],
});
```
</Callout>

<Callout title="✅ v2">
```ts
const response = db.query.users.findMany({
  orderBy: { id: "asc" },
});
```
</Callout>

##### Filtering by relations

<Callout title="❌ v1">
Was not supported in v1
</Callout>

<Callout title='✅ v2'>
Example: Get all users whose ID>10 and who have at least one post with content starting with “M”

```ts
const usersWithPosts = await db.query.usersTable.findMany({
  where: {
    id: {
      gt: 10
    },
    posts: {
      content: {
        like: 'M%'
      }
    }
  },
});
```
</Callout>

##### Using offset on related objects

<Callout title="❌ v1">
Was not supported in v1
</Callout>

<Callout title='✅ v2'>
```ts
await db.query.posts.findMany({
	limit: 5,
	offset: 2, // correct ✅
	with: {
		comments: {
			offset: 3, // correct ✅
			limit: 3,
		},
	},
});
```
</Callout>

#### How to migrate relations schema definition from v1 to v2

##### **Option 1**: Using `drizzle-kit pull`

In new version `drizzle-kit pull` supports pulling `relations.ts` file in a new syntax:

##### Step 1

<Npx>
drizzle-kit pull
</Npx>

#### Step 2 

Transfer generated relations code from `drizzle/relations.ts` to the file you are using to specify your relations 
```plaintext {4-5}
 ├ 📂 drizzle
 │ ├ 📂 meta
 │ ├ 📜 migration.sql
 │ ├ 📜 relations.ts ────────┐
 │ └ 📜 schema.ts            |
 ├ 📂 src                    │ 
 │ ├ 📂 db                   │
 │ │ ├ 📜 relations.ts <─────┘
 │ │ └ 📜 schema.ts 
 │ └ 📜 index.ts         
 └ …
```

<Callout>
`drizzle/relations.ts` includes an import of all tables from `drizzle/schema.ts`, which looks like this:
```ts
import * as schema from './schema'
```

You may need to change this import to a file where ALL your schema tables are located. 

If there are multiple schema files, you can do the following:
```ts
import * as schema1 from './schema1'
import * as schema2 from './schema2'
...
```
</Callout>

#### Step 3

Change drizzle database instance creation and provide `relations` object instead of `schema`

<Callout title='Before'>
```ts
import * as schema from './schema'
import { drizzle } from 'drizzle-orm/...'

const db = drizzle('<url>', { schema })
```
</Callout>

<Callout title='After'>
```ts
// should be imported from a file in Step 2
import { relations } from './relations'
import { drizzle } from 'drizzle-orm/...'

const db = drizzle('<url>', { relations })
```
</Callout>

<Callout>
If you had MySQL dialect, you can remove `mode` from `drizzle()` as long as it's not needed in version 2
</Callout>

##### **Option 2**: Manual migration

If you want to migrate manually, you can check our [Drizzle Relations section](/docs/relations) for the complete API reference and examples of one-to-one, one-to-many, and many-to-many relations.

#### How to migrate queries from v1 to v2

##### Migrate `where` statements

You can check our [Select Filters docs](/docs/rqb#select-filters) to see examples and a complete API reference.

With the new syntax, you can use `AND`, `OR`, `NOT`, and `RAW`, plus all the filtering operators that 
were previously available in Relations v1.

**Examples**
<CodeTabs items={["simple eq", "using AND", "using OR", "using NOT", "complex example using RAW"]}>
<CodeTab>
```ts
const response = await db.query.users.findMany({
  where: {
    age: 15,
  },
});
```
```sql {8}
select
  "d0"."id" as "id",
  "d0"."name" as "name",
  "d0"."age" as "age"
from
  "users" as "d0"
where
  "d0"."age" = 15
```
</CodeTab>
<CodeTab>
```ts
const response = await db.query.users.findMany({
  where: {
    age: 15,
    name: 'John'
  },
});
```
```sql {9-10}
select
  "d0"."id" as "id",
  "d0"."name" as "name",
  "d0"."age" as "age"
from
  "users" as "d0"
where
  (
    ("d0"."age" = 15)
    and ("d0"."name" = 'John')
  )
```
</CodeTab>
<CodeTab>
```ts
const response = await db.query.users.findMany({
  where: {
    OR: [
      {
        id: {
          gt: 10,
        },
      },
      {
        name: {
          like: "John%",
        },
      },
    ],
  },
});
```
```sql {9-10}
select
  "d0"."id" as "id",
  "d0"."name" as "name",
  "d0"."age" as "age"
from
  "users" as "d0"
where
  (
    ("d0"."id" > 10)
    or ("d0"."name" like 'John%')
  )
```
</CodeTab>
<CodeTab>
```ts
const response = await db.query.users.findMany({
  where: {
    NOT: {
      id: {
        gt: 10,
      },
    },
    name: {
      like: "John%",
    },
  },
});
```
```sql {9-10}
select
  "d0"."id" as "id",
  "d0"."name" as "name",
  "d0"."age" as "age"
from
  "users" as "d0"
where
  (
    (not ("d0"."id" > 10))
    and ("d0"."name" like 'John%')
  )
```
</CodeTab>
<CodeTab>
```ts
// schema.ts
import { integer, jsonb, pgTable, text, timestamp } from "drizzle-orm/pg-core";

export const users = pgTable("users", {
  id: integer().primaryKey(),
  name: text(),
  email: text().notNull(),
  age: integer(),
  createdAt: timestamp("created_at").defaultNow(),
  lastLogin: timestamp("last_login"),
  subscriptionEnd: timestamp("subscription_end"),
  lastActivity: timestamp("last_activity"),
  preferences: jsonb(),      // JSON column for user settings/preferences
  interests: text().array(),     // Array column for user interests
});
```
```ts
const response = await db.query.users.findMany({
  where: {
    AND: [
      {
        OR: [
          { RAW: (table) => sql`LOWER(${table.name}) LIKE 'john%'` },
          { name: { ilike: "jane%" } },
        ],
      },
      {
        OR: [
          { RAW: (table) => sql`${table.preferences}->>'theme' = 'dark'` },
          { RAW: (table) => sql`${table.preferences}->>'theme' IS NULL` },
        ],
      },
      { RAW: (table) => sql`${table.age} BETWEEN 25 AND 35` },
    ],
  },
});
```
```sql
SELECT
  "d0"."id" AS "id",
  "d0"."name" AS "name",
  "d0"."email" AS "email",
  "d0"."age" AS "age",
  "d0"."created_at" AS "createdAt",
  "d0"."last_login" AS "lastLogin",
  "d0"."subscription_end" AS "subscriptionEnd",
  "d0"."last_activity" AS "lastActivity",
  "d0"."preferences" AS "preferences",
  "d0"."interests" AS "interests"
FROM
  "users" AS "d0"
WHERE
  (
    (
      (
        (LOWER("d0"."name") LIKE 'john%')
        OR ("d0"."name" ILIKE 'jane%')
      )
    )
    AND (
      (
        ("d0"."preferences" ->> 'theme' = 'dark')
        OR ("d0"."preferences" ->> 'theme' IS NULL)
      )
    )
    AND ("d0"."age" BETWEEN 25 AND 35)
  )
```
</CodeTab>
</CodeTabs>

##### Migrate `orderBy` statements

Order by was simplified to a single object, where you specify the column and the sort direction (`asc` or `desc`)

<Callout title="❌ v1">
```ts
const response = db._query.users.findMany({
  orderBy: (users, { asc }) => [asc(users.id)],
});
```
</Callout>

<Callout title="✅ v2">
```ts
const response = db.query.users.findMany({
  orderBy: { id: "asc" },
});
```
</Callout>

##### Migrate `many-to-many` queries

Relational Queries v1 had a very complex way of managing many-to-many queries.
You had to use junction tables to query through them explicitly, and then map those tables out, like this:

```ts
const response = await db.query.users.findMany({
  with: {
    usersToGroups: {
      columns: {},
      with: {
        group: true,
      },
    },
  },
});
```

After upgrading to Relational Queries v2, your many-to-many relation will look like this:

```ts
import * as schema from './schema';
import { defineRelations } from 'drizzle-orm';

export const relations = defineRelations(schema, (r) => ({
  users: {
    groups: r.many.groups({
      from: r.users.id.through(r.usersToGroups.userId),
      to: r.groups.id.through(r.usersToGroups.groupId),
    }),
  },
  groups: {
    participants: r.many.users(),
  },
}));
```

And when you migrate your query, it will become this:

```ts
// Query example
const response = await db.query.users.findMany({
  with: {
    groups: true,
  },
});
```

### Internal changes

1. Every `drizzle` database, `session`, `migrator` and `transaction` instance updated with new generic arguments for RQB v2 queries

<Callout collapsed='Examples'>
**migrator**
<Callout type='error' title='before'>
```ts
export async function migrate<
  TSchema extends Record<string, unknown>
>(
  db: NodePgDatabase<TSchema>,
  config: MigrationConfig,
) {
  ...
}
```
</Callout>
<Callout title='now'>
```ts {1,2}
export async function migrate<TRelations extends AnyRelations>(
	db: NodePgDatabase<TRelations>,
	config: MigrationConfig,
) {
  ...
}
```
</Callout>
**session**
<Callout type='error' title='before'>
```ts
export class NodePgSession<
	TFullSchema extends Record<string, unknown>,
	TSchema extends V1.TablesRelationalConfig,
> extends PgSession<NodePgQueryResultHKT, TFullSchema, TSchema>
```
</Callout>
<Callout title='now'>
```ts {2,3}
export class NodePgSession<
	TRelations extends AnyRelations,
> extends PgAsyncSession<NodePgQueryResultHKT, TRelations>
```
</Callout>
**transaction**
<Callout type='error' title='before'>
```ts
export class NodePgTransaction<
	TFullSchema extends Record<string, unknown>,
	TSchema extends V1.TablesRelationalConfig,
> extends PgTransaction<NodePgQueryResultHKT, TFullSchema, TSchema>
```
</Callout>
<Callout title='now'>
```ts {2,3}
export class NodePgTransaction<
	TRelations extends AnyRelations,
> extends PgAsyncTransaction<NodePgQueryResultHKT, TRelations>
```
</Callout>
**driver**
<Callout type='error' title='before'>
```ts
export class NodePgDatabase<
	TSchema extends Record<string, unknown> = Record<string, never>,
> extends PgDatabase<NodePgQueryResultHKT, TSchema>
```
</Callout>
<Callout title='now'>
```ts {2,3}
export class NodePgDatabase<
	TRelations extends AnyRelations = EmptyRelations,
> extends PgAsyncDatabase<NodePgQueryResultHKT, TRelations> 
```
</Callout>
</Callout>

2. Updated `DrizzleConfig` generic with `TRelations` argument and `relations: TRelations` field

<Callout collapsed='Examples'>
<Callout type='error' title='before'>
```ts
export interface DrizzleConfig<
  TSchema extends Record<string, unknown> = Record<string, never>
> {
  logger?: boolean | Logger;
  schema?: TSchema;
  casing?: Casing;
}
```
</Callout>

<Callout title='now'>
```ts {2,5}
export interface DrizzleConfig<
	TRelationConfigs extends AnyRelations = EmptyRelations,
> {
	logger?: boolean | Logger | undefined;
	relations?: TRelationConfigs | undefined;
	cache?: Cache | undefined;
	jit?: boolean | undefined;
}
```
</Callout>
</Callout>

3. The following entities have been removed from `drizzle-orm` and `drizzle-orm/relations`. The original imports now 
include new types used by Relational Queries v2, so make sure to update your imports if you intend to use the older types:

<Callout collapsed='A list of all removed entities'>
- `Relations`
- `TableRelationsKeysOnly`
- `ExtractTableRelationsFromSchema`
- `ExtractRelationsFromTableExtraConfigSchema`
- `getOperators`
- `FindTableByDBName`
- `RelationalSchemaConfig`
- `RelationConfig`
- `extractTablesRelationalConfig`
- `relations`
- `createOne`
- `createMany`
- `NormalizedRelation`
- `normalizeRelation`
- `createTableRelationsHelpers`
- `TableRelationsHelpers`
</Callout>

4. In the same manner, `${dialect}-core/query-builders/query` files were updated with RQB v2's alternatives

<Callout collapsed='Examples'>
```ts
import { RelationalQueryBuilder, PgRelationalQuery } from 'drizzle-orm/pg-core/query-builders/query';
```
</Callout>


Source: https://orm.drizzle.team/docs/pg/relations

import Tab from '@mdx/Tab.astro';
import Tabs from '@mdx/Tabs.astro';
import IsSupportedChipGroup from '@mdx/IsSupportedChipGroup.astro';
import Callout from '@mdx/Callout.astro';
import Section from '@mdx/Section.astro';
import Prerequisites from "@mdx/Prerequisites.astro";
import CodeTab from '@mdx/CodeTab.astro';
import CodeTabs from '@mdx/CodeTabs.astro';
import Npm from '@mdx/Npm.astro';

# Drizzle relations

<Npm>
 drizzle-orm@rc
 drizzle-kit@rc -D
</Npm>

<br/>

<Prerequisites>  
  - **Relations Fundamentals** - get familiar with the concepts of foreign key constraints, soft relations, database normalization, etc - [read here](/docs/relations-schema-declaration)
  - **Declare schema** - get familiar with how to define drizzle schemas - [read here](/docs/sql-schema-declaration)
  - **Database connection** - get familiar with how to connect to database using drizzle - [read here](/docs/get-started-postgresql)
</Prerequisites>

The sole purpose of Drizzle relations is to let you query your relational data in the most simple and concise way:

<CodeTabs items={["Relational queries", "Select with joins"]}>
<Section>
```ts
import { drizzle } from 'drizzle-orm/...';
import { defineRelations } from 'drizzle-orm';
import * as p from 'drizzle-orm/pg-core';

export const users = p.pgTable('users', {
	id: p.integer().primaryKey(),
	name: p.text().notNull()
});

export const posts = p.pgTable('posts', {
	id: p.integer().primaryKey(),
	content: p.text().notNull(),
	ownerId: p.integer('owner_id'),
});

const relations = defineRelations({ users, posts }, (r) => ({
	posts: {
		author: r.one.users({
			from: r.posts.ownerId,
			to: r.users.id,
		}),
	}
}))

const db = drizzle({ client, relations });

const result = await db.query.posts.findMany({
  with: {
    author: true,
  },
});
```
```ts
[{
  id: 10,
  content: "My first post!",
  ownerId: 14,
  author: {
    id: 1,
    name: "Alex"
  }
}]
```
</Section>
<Section>
```ts
import { drizzle } from 'drizzle-orm/...';
import { eq } from 'drizzle-orm';
import { posts, users } from './schema';

const db = drizzle({ client });

const res = await db.select()
                    .from(posts)
                    .leftJoin(users, eq(posts.ownerId, users.id))
                    .orderBy(posts.id)

const mappedResult = ...
```
</Section>
</CodeTabs>

### `one()`
Here is a list of all fields available for `.one()` in drizzle relations

```ts {3-11}
const relations = defineRelations({ users, posts }, (r) => ({
	posts: {
		author: r.one.users({
			from: r.posts.ownerId,
			to: r.users.id,
			optional: false,
      alias: 'custom_name',
			where: {
				verified: true,
			}
		}),
	}
}))
```

- `author` key is a custom key that appears in the `posts` object when using Drizzle relational queries.
- `r.one.users` defines that `author` will be a single object from the `users` table rather than an array of objects.
- `from: r.posts.ownerId` specifies the table from which we are establishing a soft relation. 
In this case, the relation starts from the `ownerId` column in the `posts` table.
- `to: r.users.id` specifies the table to which we are establishing a soft relation. 
In this case, the relation points to the `id` column in the `users` table.
- `optional: false` at the type level makes the `author` key in the posts object `required`. 
This should be used when you are certain that this specific entity will always exist.
- `alias` is used to add a specific alias to relationships between tables. If you have multiple identical relationships between two tables, you should 
differentiate them using `alias`
- `where` condition can be used for polymorphic relations. It fetches relations based on a `where` statement.
For example, in the case above, only `verified authors` will be retrieved. Learn more about polymorphic relations [here](/docs/relations-schema-declaration#polymorphic-relations).

### `many()`

Here is a list of all fields available for `.many()` in drizzle relations

```ts {3-10}
const relations = defineRelations({ users, posts }, (r) => ({
	users: {
		feed: r.many.posts({
			from: r.users.id,
			to: r.posts.ownerId,
			alias: 'custom_name',
			where: {
				approved: true,
			}
		}),
	}
}))
```

- `feed` key is a custom key that appears in the `users` object when using Drizzle relational queries.
- `r.many.posts` defines that `feed` will be an array of objects from the `posts` table rather than just an object
- `from: r.users.id` specifies the table from which we are establishing a soft relation. 
In this case, the relation starts from the `id` column in the `users` table.
- `to: r.posts.ownerId` specifies the table to which we are establishing a soft relation. 
In this case, the relation points to the `ownerId` column in the `posts` table.
- `alias` is used to add a specific alias to relationships between tables. If you have multiple identical relationships between two tables, you should 
differentiate them using `alias`
- `where` condition can be used for polymorphic relations. It fetches relations based on a `where` statement.
For example, in the case above, only `approved posts` will be retrieved. Learn more about polymorphic relations [here](/docs/relations-schema-declaration#polymorphic-relations).

## ---

### One-to-one
Drizzle ORM provides you an API to define `one-to-one` relations between tables with the `defineRelations` function.

An example of a `one-to-one` relation between users and users, where a user can invite another (this example uses a self reference):

```typescript copy {10-17}
import { pgTable, text, integer } from 'drizzle-orm/pg-core';
import { defineRelations } from 'drizzle-orm';

export const users = pgTable('users', {
	id: integer().primaryKey(),
	name: text(),
	invitedBy: integer('invited_by'),
});

export const relations = defineRelations({ users }, (r) => ({
	users: {
		invitee: r.one.users({
			from: r.users.invitedBy,
			to: r.users.id,
		})
	}
}));
```

Another example would be a user having a profile information stored in separate table. In this case, because the foreign key is stored in the "profile_info" table, the user relation have neither fields or references. This tells Typescript that `user.profileInfo` is nullable:

```typescript copy {15-22}
import { pgTable, serial, text, integer, jsonb } from 'drizzle-orm/pg-core';
import { defineRelations } from 'drizzle-orm';

export const users = pgTable('users', {
	id: integer().primaryKey(),
	name: text(),
});

export const profileInfo = pgTable('profile_info', {
	id: serial().primaryKey(),
	userId: integer('user_id').references(() => users.id),
	metadata: jsonb(),
});

export const relations = defineRelations({ users, profileInfo }, (r) => ({
	users: {
		profileInfo: r.one.profileInfo({
			from: r.users.id,
			to: r.profileInfo.userId,
		})
	}
}));

const user = await db.query.users.findFirst({ with: { profileInfo: true } });
//____^? type { id: number, name: string | null, profileInfo: { ... } | null  }
```

### One-to-many
Drizzle ORM provides you an API to define `one-to-many` relations between tables with `defineRelations` function. 

Example of `one-to-many` relation between users and posts they've written:

```typescript copy {15-25}
import { pgTable, text, integer } from 'drizzle-orm/pg-core';
import { defineRelations } from 'drizzle-orm';

export const users = pgTable('users', {
	id: integer('id').primaryKey(),
	name: text('name'),
});

export const posts = pgTable('posts', {
	id: integer('id').primaryKey(),
	content: text('content'),
	authorId: integer('author_id'),
});

export const relations = defineRelations({ users, posts }, (r) => ({
  posts: {
    author: r.one.users({
      from: r.posts.authorId,
      to: r.users.id,
    }),
  },
  users: {
    posts: r.many.posts(),
  },
}));
```

Now lets add comments to the posts:
```typescript copy {9-14,22,27-32}
...

export const posts = pgTable('posts', {
	id: integer('id').primaryKey(),
	content: text('content'),
	authorId: integer('author_id'),
});

export const comments = pgTable("comments", {
  id: integer().primaryKey(),
  text: text(),
  authorId: integer("author_id"),
  postId: integer("post_id"),
});

export const relations = defineRelations({ users, posts, comments }, (r) => ({
  posts: {
    author: r.one.users({
      from: r.posts.authorId,
      to: r.users.id,
    }),
    comments: r.many.comments(),
  },
  users: {
    posts: r.many.posts(),
  },
  comments: {
    post: r.one.posts({
      from: r.comments.postId,
      to: r.posts.id,
    }),
  },
}));
```


### Many-to-many
Drizzle ORM provides you an API to define `many-to-many` relations between tables through so called `junction` or `join` tables,
they have to be explicitly defined and store associations between related tables.  

Example of `many-to-many` relation between users and groups we are using `through` to bypass junction table selection and directly select many `groups` for each `user`.
```typescript copy {27-39}
import { defineRelations } from 'drizzle-orm';
import { integer, pgTable, primaryKey, text } from 'drizzle-orm/pg-core';

export const users = pgTable('users', {
  id: integer().primaryKey(),
  name: text(),
});

export const groups = pgTable('groups', {
  id: integer().primaryKey(),
  name: text(),
});

export const usersToGroups = pgTable(
  'users_to_groups',
  {
    userId: integer('user_id')
      .notNull()
      .references(() => users.id),
    groupId: integer('group_id')
      .notNull()
      .references(() => groups.id),
  },
  (t) => [primaryKey({ columns: [t.userId, t.groupId] })],
);

export const relations = defineRelations({ users, groups, usersToGroups },
  (r) => ({
    users: {
      groups: r.many.groups({
        from: r.users.id.through(r.usersToGroups.userId),
        to: r.groups.id.through(r.usersToGroups.groupId),
      }),
    },
    groups: {
      participants: r.many.users(),
    },
  })
);
```

**Query example:**
```ts
const res = await db.query.users.findMany({
  with: { 
    groups: true 
  },
});

// response type
type Response = {
  id: number;
  name: string | null;
  groups: {
    id: number;
    name: string | null;
  }[];
}[];
```

### Predefined filters

Predefined `where` statements in Drizzle's relation definitions are a type of polymorphic relations implementation, but it's not fully it. Essentially, they allow you to
connect tables not only by selecting specific columns but also through custom `where` statements. Let's look at some examples:

We can define a relation between `groups` and `users` so that when querying group's users, we only retrieve those whose `verified` column is set to `true`
<CodeTabs items={["Relations", "Schema"]}>
<Section>
```ts
import { defineRelations } from "drizzle-orm";
import * as schema from './schema';

export const relations = defineRelations(schema,(r) => ({
    groups: {
      verifiedUsers: r.many.users({
        from: r.groups.id.through(r.usersToGroups.groupId),
        to: r.users.id.through(r.usersToGroups.userId),
        where: {
          verified: true,
        },
      }),
    },
  })
);

...

await db.query.groups.findMany({
    with: {
      verifiedUsers: true,
    },
});
```
</Section>
<Section>
```ts
import * as p from "drizzle-orm/pg-core";

export const users = p.pgTable("users", {
  id: p.integer().primaryKey(),
  name: p.text().notNull(),
  verified: p.boolean().notNull(),
});

export const groups = p.pgTable("groups", {
  id: p.integer().primaryKey(),
  title: p.text().notNull(),
});

export const usersToGroups = p.pgTable(
  "users_to_groups",
  {
    userId: p
      .integer("user_id")
      .notNull()
      .references(() => users.id, { onDelete: "cascade" }),
    groupId: p
      .integer("group_id")
      .notNull()
      .references(() => groups.id, { onDelete: "cascade" }),
  },
  (t) => [p.primaryKey({ columns: [t.groupId, t.userId] })]
);
```
</Section>
</CodeTabs>

<Callout type='warning'>
You can only specify filters on the target (to) table. So in this example, the where clause will only include columns from the `users` table since we are establishing a relation **TO** users

```ts {7}
export const relations = defineRelations(schema,(r) => ({
    groups: {
      verifiedUsers: r.many.users({
        from: r.groups.id.through(r.usersToGroups.groupId),
        to: r.users.id.through(r.usersToGroups.userId),
        where: {
          verified: true,
        },
      }),
    },
  })
);
```
</Callout>

## ---

### Relations Parts

In a case you need to separate relations config into several parts you can use `defineRelationsPart` helpers

```ts
import { defineRelations, defineRelationsPart } from 'drizzle-orm';
import * as schema from "./schema";

export const relations = defineRelations(schema, (r) => ({
  users: {
    invitee: r.one.users({
      from: r.users.invitedBy,
      to: r.users.id,
    }),
    posts: r.many.posts(),
  }
}));

export const part = defineRelationsPart(schema, (r) => ({
  posts: {
    author: r.one.users({
      from: r.posts.authorId,
      to: r.users.id,
    }),
  }
}));
```

and then you can provide it to the db instance

```ts
const db = drizzle(process.env.DB_URL, { relations: { ...relations, ...part } })
```

<Callout type='warning'>
There are a few rules you would need to follow to make sure it `defineRelationsParts` works as expected

**Rule 1**: If you specify reltions with parts, when passing it to drizzle db function you would need to specify it in the right order(main relations goes first)
```ts
// ✅
const db = drizzle(process.env.DB_URL, { relations: { ...relations, ...part } })

// ❌
const db = drizzle(process.env.DB_URL, { relations: { ...part, ...relations } })
```

<Callout collapsed="Why it's important?">
Even if there will be no type or runtime error, this is how "..." works with objects. As long as main relation 
recursively infer all tables names, so it can be available in autocomplete. Here is an example:

```ts
export const relations = defineRelations(schema, (r) => ({
  users: {
    invitee: r.one.users({
      from: r.users.invitedBy,
      to: r.users.id,
    }),
    posts: r.many.posts(),
  }
}));

export const part = defineRelationsPart(schema, (r) => ({
  posts: {
    author: r.one.users({
      from: r.posts.authorId,
      to: r.users.id,
    }),
  }
}));
```

Here `relations` and `part` can be represented and this object:
```json
// relations
{
  "users": {"invitee": {...}, "posts": {...}},
  // added here, so all tables from schema will exist in autocomplete
  "posts": {}
}

// part
{
  "posts": {"author": {...}}
}
```

Having `{ ...relations, ...part }` will result in 
```json
{
  "users": {"invitee": {...}, "posts": {...}},
  "posts": {"author": {...}}
}
```

and having `{ ...relations, ...part }` will result in
```json
{
  "users": {"invitee": {...}, "posts": {...}},
  // As you can see in the final object, posts relations information will be lost
  "posts": {}
}
```

</Callout>

**Rule 2**: You should have min relations, so drizzle can infer all of the table for autocomplete. If you want to have only parts, then 
one of your parts should be empty, like this:

```ts
export const mainPart = defineRelationsPart(schema);
```

In this case, all tables will be inferred correctly, and you'll have complete information about your schema
</Callout>

## ---

### Performance

When working with relations in Drizzle ORM, especially in applications with 
significant data or complex queries, optimizing database performance is crucial.  
Indexes play a vital role in speeding up data retrieval, particularly when querying 
related data. This section outlines recommended indexing strategies for each type 
of relationship defined using Drizzle ORM.

##### One-to-one Relationships

In a one-to-one relationship, like the "user invites user" example or the
"user has profile info" example, the key performance consideration is efficient joining 
of the related tables.

<Callout>
For optimal performance in one-to-one relationships, you should create an index 
on the foreign key column in the table that is being referenced 
(the "target" table in the relation).
</Callout>

<Callout collapsed='Why it is important'>
When you query data with related one-to-one information, Drizzle performs a JOIN operation. An index on the foreign key column allows the database to quickly 
locate the related row in the target table, significantly speeding up the join process.
</Callout>

**Example:**
```typescript
import * as p from 'drizzle-orm/pg-core';
import { defineRelations } from 'drizzle-orm';

export const users = p.pgTable('users', {
	id: p.integer().primaryKey(),
	name: p.text(),
});

export const profileInfo = p.pgTable('profile_info', {
	id: p.integer().primaryKey(),
	userId: p.integer('user_id').references(() => users.id),
	metadata: p.jsonb(),
});

export const relations = defineRelations({ users, profileInfo }, (r) => ({
	users: {
		profileInfo: r.one.profileInfo({
			from: r.users.id,
			to: r.profileInfo.userId,
		})
	}
}));
```

To optimize queries fetching user data along with their profile information, 
you should create an index on the `userId` column in the `profile_info` table.

```typescript {13-15}
import * as p from 'drizzle-orm/pg-core';
import { defineRelations } from 'drizzle-orm';

export const users = p.pgTable('users', {
	id: p.integer().primaryKey(),
	name: p.text(),
});

export const profileInfo = p.pgTable('profile_info', {
	id: p.integer().primaryKey(),
	userId: p.integer('user_id').references(() => users.id),
	metadata: p.jsonb(),
}, (table) => [
  p.index('profile_info_user_id_idx').on(table.userId)
]);

export const relations = defineRelations({ users, profileInfo }, (r) => ({
	users: {
		profileInfo: r.one.profileInfo({
			from: r.users.id,
			to: r.profileInfo.userId,
		})
	}
}));
```
```sql
CREATE INDEX "profile_info_user_id_idx" ON "profile_info" ("user_id");
```

#### One-to-many Relationships

Similar to one-to-one relationships, one-to-many relations benefit significantly 
from indexing to optimize join operations. Consider the "users and posts" example where one user can have many posts.

<Callout>
For one-to-many relationships, create an index on the foreign key column in the table that represents the "many" side of the relationship (the table with the foreign key referencing the "one" side).
</Callout>

<Callout collapsed='Why it is important'>
When you fetch a user with their posts or posts with their authors, joins are performed.
Indexing the foreign key (`authorId` in `posts` table) allows the database to efficiently 
retrieve all posts associated with a given user or quickly find the author of a post.
</Callout>

**Example:**
```typescript
import * as p from "drizzle-orm/pg-core";
import { defineRelations } from 'drizzle-orm';

export const users = p.pgTable('users', {
	id: p.integer().primaryKey(),
	name: p.text(),
});

export const posts = p.pgTable('posts', {
	id: p.integer().primaryKey(),
	content: p.text(),
	authorId: p.integer('author_id'),
});

export const relations = defineRelations({ users, posts }, (r) => ({
  posts: {
    author: r.one.users({
      from: r.posts.authorId,
      to: r.users.id,
    }),
  },
  users: {
    posts: r.many.posts(),
  },
}));
```

To optimize queries involving users and their posts, create an index on the `authorId` column in the `posts` table.

```typescript {13-15}
import * as p from "drizzle-orm/pg-core";
import { defineRelations } from 'drizzle-orm';

export const users = p.pgTable('users', {
	id: p.integer().primaryKey(),
	name: p.text(),
});

export const posts = p.pgTable('posts', {
	id: p.integer().primaryKey(),
	content: p.text(),
	authorId: p.integer('author_id'),
}, (t) => [
  p.index('posts_author_id_idx').on(t.authorId)
]);

export const relations = defineRelations({ users, posts }, (r) => ({
  posts: {
    author: r.one.users({
      from: r.posts.authorId,
      to: r.users.id,
    }),
  },
  users: {
    posts: r.many.posts(),
  },
}));
```
```sql
CREATE INDEX "posts_author_id_idx" ON "posts" ("author_id");
```

#### Many-to-many Relationships

Many-to-many relationships, implemented using junction tables, require a slightly 
more nuanced indexing strategy to ensure optimal query performance. 
Consider the "users and groups" example with the `usersToGroups` junction table.

<Callout>
For many-to-many relationships, it is generally recommended to create the following 
indexes on the junction table:
1.  **Index on each foreign key column individually:** This optimizes queries that 
filter or join based on a single side of the relationship 
(e.g., finding all groups for a user OR all users in a group).
2.  **Composite index on both foreign key columns together:** This is crucial for 
efficiently resolving the many-to-many relationship itself. It speeds up queries that need to find the connections between both entities.
</Callout>

<Callout collapsed='Why it is important'>
When querying many-to-many relations, especially when using `through` in Drizzle ORM, the database needs to efficiently navigate the junction table.

- Indexes on individual foreign key columns (`userId`, `groupId` in `usersToGroups`) help when you are querying from one side to find the other (e.g., "find groups for a user").
- The composite index on `(userId, groupId)` in `usersToGroups` is particularly important for quickly finding all relationships defined in the junction table. This is used when Drizzle ORM resolves the `many-to-many` relation to fetch related entities.
</Callout>

**Example:**

In the "users and groups" example, the `usersToGroups` junction table connects `users` and `groups`.

```typescript
import { defineRelations } from 'drizzle-orm';
import * as p from 'drizzle-orm/pg-core';

export const users = p.pgTable('users', {
  id: p.integer().primaryKey(),
  name: p.text(),
});

export const groups = p.pgTable('groups', {
  id: p.integer().primaryKey(),
  name: p.text(),
});

export const usersToGroups = p.pgTable(
  'users_to_groups',
  {
    userId: p.integer('user_id')
      .notNull()
      .references(() => users.id),
    groupId: p.integer('group_id')
      .notNull()
      .references(() => groups.id),
  },
  (t) => [p.primaryKey({ columns: [t.userId, t.groupId] })],
);

export const relations = defineRelations({ users, groups, usersToGroups },
  (r) => ({
    users: {
      groups: r.many.groups({
        from: r.users.id.through(r.usersToGroups.userId),
        to: r.groups.id.through(r.usersToGroups.groupId),
      }),
    },
    groups: {
      participants: r.many.users(),
    },
  })
);
```

To optimize queries for users and groups, create indexes on `usersToGroups` table as follows:

```typescript {26-28}
import { defineRelations } from 'drizzle-orm';
import * as p from 'drizzle-orm/pg-core';

export const users = p.pgTable('users', {
  id: p.integer().primaryKey(),
  name: p.text(),
});

export const groups = p.pgTable('groups', {
  id: p.integer().primaryKey(),
  name: p.text(),
});

export const usersToGroups = p.pgTable(
  'users_to_groups',
  {
    userId: p.integer('user_id')
      .notNull()
      .references(() => users.id),
    groupId: p.integer('group_id')
      .notNull()
      .references(() => groups.id),
  },
  (t) => [
    p.primaryKey({ columns: [t.userId, t.groupId] }),
    p.index('users_to_groups_user_id_idx').on(t.userId),
    p.index('users_to_groups_group_id_idx').on(t.groupId),
    p.index('users_to_groups_composite_idx').on(t.userId, t.groupId),
  ],
);

export const relations = defineRelations({ users, groups, usersToGroups },
  (r) => ({
    users: {
      groups: r.many.groups({
        from: r.users.id.through(r.usersToGroups.userId),
        to: r.groups.id.through(r.usersToGroups.groupId),
      }),
    },
    groups: {
      participants: r.many.users(),
    },
  })
);
```
```sql
CREATE INDEX "users_to_groups_user_id_idx" ON "users_to_groups" ("user_id");
CREATE INDEX "users_to_groups_group_id_idx" ON "users_to_groups" ("group_id");
CREATE INDEX "users_to_groups_composite_idx" ON "users_to_groups" ("user_id","group_id");
```

By applying these indexing strategies, you can significantly improve the performance of your Drizzle ORM applications when working with relational data, especially as your data volume grows and your queries become more complex. Remember to choose the indexes that best suit your specific query patterns and application needs.

## ---

### Foreign keys

You might've noticed that `relations` look similar to foreign keys — they even have a `references` property. So what's the difference?

While foreign keys serve a similar purpose, defining relations between tables, they work on a different level compared to `relations`.

Foreign keys are a database level constraint, they are checked on every `insert`/`update`/`delete` operation and throw an error if a constraint is violated.
On the other hand, `relations` are a higher level abstraction, they are used to define relations between tables on the application level only.
They do not affect the database schema in any way and do not create foreign keys implicitly.

What this means is `relations` and foreign keys can be used together, but they are not dependent on each other.
You can define `relations` without using foreign keys (and vice versa), which allows them to be used with databases that do not support foreign keys.

The following two examples will work exactly the same in terms of querying the data using Drizzle relational queries.

<CodeTabs items={["schema1.ts", "schema2.ts"]}>
<CodeTab>
```ts {15}
export const users = p.pgTable("users", {
  id: p.integer().primaryKey(),
  name: p.text(),
});

export const profileInfo = p.pgTable("profile_info", {
  id: p.integer().primaryKey(),
  userId: p.integer("user_id"),
  metadata: p.jsonb(),
});

export const relations = defineRelations({ users, profileInfo }, (r) => ({
  users: {
    profileInfo: r.one.profileInfo({
      from: r.users.id,
      to: r.profileInfo.userId,
    }),
  },
}));
```
</CodeTab>
<CodeTab>
```ts {15}
export const users = p.pgTable("users", {
  id: p.integer().primaryKey(),
  name: p.text(),
});

export const profileInfo = p.pgTable("profile_info", {
  id: p.integer().primaryKey(),
  userId: p.integer("user_id").references(() => users.id),
  metadata: p.jsonb(),
});

export const relations = defineRelations({ users, profileInfo }, (r) => ({
  users: {
    profileInfo: r.one.profileInfo({
      from: r.users.id,
      to: r.profileInfo.userId,
    }),
  },
}));
```
</CodeTab>
</CodeTabs>

### Disambiguating relations

Drizzle also provides the `alias` option as a way to disambiguate
relations when you define multiple of them between the same two tables. For
example, if you define a `posts` table that has the `author` and `reviewer`
relations.

```ts {19,22,29,34}
import { pgTable, integer, text } from 'drizzle-orm/pg-core';
import { defineRelations } from 'drizzle-orm';
 
export const users = pgTable('users', {
	id: integer('id').primaryKey(),
	name: text('name'),
});

export const posts = pgTable('posts', {
	id: integer('id').primaryKey(),
	content: text('content'),
	authorId: integer('author_id'),
	reviewerId: integer('reviewer_id'),
});
 
export const relations = defineRelations({ users, posts }, (r) => ({
  users: {
    posts: r.many.posts({
      alias: "author",
    }),
    reviewedPosts: r.many.posts({
      alias: "reviewer",
    }),
  },
  posts: {
    author: r.one.users({
      from: r.posts.authorId,
      to: r.users.id,
      alias: "author",
    }),
    reviewer: r.one.users({
      from: r.posts.authorId,
      to: r.users.id,
      alias: "reviewer",
    }),
  },
}));
```


Source: https://orm.drizzle.team/docs/pg/rls

import Callout from '@mdx/Callout.astro';

# Row-Level Security (RLS)

With Drizzle, you can enable Row-Level Security (RLS) for any Postgres table, create policies with various options, and define and manage the roles those policies apply to.

Drizzle supports a raw representation of Postgres policies and roles that can be used in any way you want. This works with popular Postgres database providers such as `Neon` and `Supabase`.

In Drizzle, we have specific predefined RLS roles and functions for RLS with both database providers, but you can also define your own logic.

## Enable RLS

If you just want to enable RLS on a table without adding policies, you can use `pgTable.withRLS(...)`

As mentioned in the PostgreSQL documentation:

> If no policy exists for the table, a default-deny policy is used, meaning that no rows are visible or can be modified. 
Operations that apply to the whole table, such as TRUNCATE and REFERENCES, are not subject to row security.

```ts
import { integer, pgTable } from 'drizzle-orm/pg-core';

export const users = pgTable.withRLS('users', {
	id: integer(),
});
```

<Callout title='important'>
If you add a policy to a table, RLS will be enabled automatically. So, there's no need to explicitly enable RLS when adding policies to a table.
</Callout>

## Roles

Currently, Drizzle supports defining roles with a few different options, as shown below. Support for more options will be added in a future release.

```ts
import { pgRole } from 'drizzle-orm/pg-core';

export const admin = pgRole('admin', { createRole: true, createDb: true, inherit: true });
```

If a role already exists in your database, and you don't want drizzle-kit to 'see' it or include it in migrations, you can mark the role as existing.

```ts
import { pgRole } from 'drizzle-orm/pg-core';

export const admin = pgRole('admin').existing();
```

## Policies

To fully leverage RLS, you can define policies within a Drizzle table.

<Callout title='info'>
In PostgreSQL, policies should be linked to an existing table. Since policies are always associated with a specific table, we decided that policy definitions should be defined as a parameter of `pgTable`
</Callout>

**Example of pgPolicy with all available properties**
```ts
import { sql } from 'drizzle-orm';
import { integer, pgPolicy, pgRole, pgTable } from 'drizzle-orm/pg-core';

export const admin = pgRole('admin');

export const users = pgTable('users', {
	id: integer(),
}, (t) => [
	pgPolicy('policy', {
		as: 'permissive',
		to: admin,
		for: 'delete',
		using: sql``,
		withCheck: sql``,
	}),
]);
```

**Policy options**
|                          |                                                                                                                                           |
| :----------------------- | :---------------------------------------------------------------------------------------------------------------------------------------- |
| `as`                     | Possible values are `permissive` or `restrictive`                                                                                         |
| `to`                     | Specifies the role to which the policy applies. Possible values include `public`, `current_role`, `current_user`, `session_user`, or any other role name as a string. You can also reference a `pgRole` object. |
| `for`                    | Defines the commands this policy will be applied to. Possible values are `all`, `select`, `insert`, `update`, `delete`.                   |
| `using`                  | The SQL statement that will be applied to the `USING` part of the policy creation statement.                                              |
| `withCheck`              | An SQL statement that will be applied to the `WITH CHECK` part of the policy creation statement.                                          |

**Link Policy to an existing table**

There are situations where you need to link a policy to an existing table in your database. 
The most common use case is with database providers like `Neon` or `Supabase`, where you need to add a policy 
to their existing tables. In this case, you can use the `.link()` API

```ts
import { sql } from "drizzle-orm";
import { pgPolicy } from "drizzle-orm/pg-core";
import { authenticatedRole, realtimeMessages } from "drizzle-orm/supabase";

export const policy = pgPolicy("authenticated role insert policy", {
  for: "insert",
  to: authenticatedRole,
  using: sql``,
}).link(realtimeMessages);
```

{/* <Callout title='important'>
<Callout> */}

## Migrations

If you are using drizzle-kit to manage your schema and roles, there may be situations where you want to refer to roles that are not defined in your Drizzle schema. In such cases, you may want drizzle-kit to skip managing these roles without having to define each role in your drizzle schema and marking it with `.existing()`.

In these cases, you can use `entities.roles` in `drizzle.config.ts`. For a complete reference, refer to the the [drizzle.config.ts](/docs/drizzle-config-file) documentation.

By default, `drizzle-kit` does not manage roles for you, so you will need to enable this feature in `drizzle.config.ts`.

```ts {12-14}
// drizzle.config.ts
import { defineConfig } from "drizzle-kit";

export default defineConfig({
  dialect: 'postgresql',
  schema: "./drizzle/schema.ts",
  dbCredentials: {
    url: process.env.DATABASE_URL!
  },
  verbose: true,
  strict: true,
  entities: {
    roles: true
  }
});
```

In case you need additional configuration options, let's take a look at a few more examples.

**You have an `admin` role and want to exclude it from the list of manageable roles**

```ts
// drizzle.config.ts
import { defineConfig } from "drizzle-kit";

export default defineConfig({
  ...
  entities: {
    roles: {
      exclude: ['admin']
    }
  }
});
```

**You have an `admin` role and want to include it in the list of manageable roles**

```ts
// drizzle.config.ts
import { defineConfig } from "drizzle-kit";

export default defineConfig({
  ...
  entities: {
    roles: {
      include: ['admin']
    }
  }
});
```

**If you are using `Neon` and want to exclude Neon-defined roles, you can use the provider option**

```ts
// drizzle.config.ts
import { defineConfig } from "drizzle-kit";

export default defineConfig({
  ...
  entities: {
    roles: {
      provider: 'neon'
    }
  }
});
```

**If you are using `Supabase` and want to exclude Supabase-defined roles, you can use the provider option**

```ts
// drizzle.config.ts
import { defineConfig } from "drizzle-kit";

export default defineConfig({
  ...
  entities: {
    roles: {
      provider: 'supabase'
    }
  }
});
```

<Callout title='important'>
You may encounter situations where Drizzle is slightly outdated compared to new roles specified by your database provider. 
In such cases, you can use the `provider` option and `exclude` additional roles:

```ts
// drizzle.config.ts
import { defineConfig } from "drizzle-kit";

export default defineConfig({
  ...
  entities: {
    roles: {
      provider: 'supabase',
      exclude: ['new_supabase_role']
    }
  }
});
```
</Callout>

## RLS on views

With Drizzle, you can also specify RLS policies on views. For this, you need to use `security_invoker` in the view's WITH options. Here is a small example:

```ts {5}
...

export const roomsUsersProfiles = pgView("rooms_users_profiles")
  .with({
    securityInvoker: true,
  })
  .as((qb) =>
    qb
      .select({
        ...getColumns(roomsUsers),
        email: profiles.email,
      })
      .from(roomsUsers)
      .innerJoin(profiles, eq(roomsUsers.userId, profiles.id))
  );
```

## Using with Neon

The Neon Team helped us implement their vision of a wrapper on top of our raw policies API. We defined a specific 
`/neon` import with the `crudPolicy` function that includes predefined functions and Neon's default roles.

Here's an example of how to use the `crudPolicy` function:

```ts
import { crudPolicy } from 'drizzle-orm/neon';
import { integer, pgRole, pgTable } from 'drizzle-orm/pg-core';

export const admin = pgRole('admin');

export const users = pgTable('users', {
	id: integer(),
}, (t) => [
	crudPolicy({ role: admin, read: true, modify: false }),
]);
```

This policy is equivalent to:

```ts
import { sql } from 'drizzle-orm';
import { integer, pgPolicy, pgRole, pgTable } from 'drizzle-orm/pg-core';

export const admin = pgRole('admin');

export const users = pgTable('users', {
	id: integer(),
}, (t) => [
	pgPolicy(`crud-${admin.name}-policy-insert`, {
		for: 'insert',
		to: admin,
		withCheck: sql`false`,
	}),
	pgPolicy(`crud-${admin.name}-policy-update`, {
		for: 'update',
		to: admin,
		using: sql`false`,
		withCheck: sql`false`,
	}),
	pgPolicy(`crud-${admin.name}-policy-delete`, {
		for: 'delete',
		to: admin,
		using: sql`false`,
	}),
	pgPolicy(`crud-${admin.name}-policy-select`, {
		for: 'select',
		to: admin,
		using: sql`true`,
	}),
]);
```

`Neon` exposes predefined `authenticated` and `anaonymous` roles and related functions. If you are using `Neon` for RLS, you can use these roles, which are marked as existing, and the related functions in your RLS queries.

```ts
// drizzle-orm/neon
export const authenticatedRole = pgRole('authenticated').existing();
export const anonymousRole = pgRole('anonymous').existing();

export const authUid = (userIdColumn: AnyPgColumn) => sql`(select auth.user_id() = ${userIdColumn})`;

export const neonIdentitySchema = pgSchema('neon_identity');

export const usersSync = neonIdentitySchema.table('users_sync', {
  rawJson: jsonb('raw_json').notNull(),
  id: text().primaryKey().notNull(),
  name: text(),
  email: text(),
  createdAt: timestamp('created_at', { withTimezone: true, mode: 'string' }),
  deletedAt: timestamp('deleted_at', { withTimezone: true, mode: 'string' }),
});
```

For example, you can use the `Neon` predefined roles and functions like this:

```ts
import { sql } from 'drizzle-orm';
import { authenticatedRole } from 'drizzle-orm/neon';
import { integer, pgPolicy, pgRole, pgTable } from 'drizzle-orm/pg-core';

export const admin = pgRole('admin');

export const users = pgTable('users', {
	id: integer(),
}, (t) => [
	pgPolicy(`policy-insert`, {
		for: 'insert',
		to: authenticatedRole,
		withCheck: sql`false`,
	}),
]);
```

## Using with Supabase

We also have a `/supabase` import with a set of predefined roles marked as existing, which you can use in your schema. 
This import will be extended in a future release with more functions and helpers to make using RLS and `Supabase` simpler.

```ts
// drizzle-orm/supabase
export const anonRole = pgRole('anon').existing();
export const authenticatedRole = pgRole('authenticated').existing();
export const serviceRole = pgRole('service_role').existing();
export const postgresRole = pgRole('postgres_role').existing();
export const supabaseAuthAdminRole = pgRole('supabase_auth_admin').existing();
```

For example, you can use the `Supabase` predefined roles like this:

```ts
import { sql } from 'drizzle-orm';
import { serviceRole } from 'drizzle-orm/supabase';
import { integer, pgPolicy, pgRole, pgTable } from 'drizzle-orm/pg-core';

export const admin = pgRole('admin');

export const users = pgTable('users', {
	id: integer(),
}, (t) => [
	pgPolicy(`policy-insert`, {
		for: 'insert',
		to: serviceRole,
		withCheck: sql`false`,
	}),
]);
```

The `/supabase` import also includes predefined tables and functions that you can use in your application

```ts
// drizzle-orm/supabase

const auth = pgSchema('auth');
export const authUsers = auth.table('users', {
	id: uuid().primaryKey().notNull(),
});

const realtime = pgSchema('realtime');
export const realtimeMessages = realtime.table(
	'messages',
	{
		id: bigserial({ mode: 'bigint' }).primaryKey(),
		topic: text().notNull(),
		extension: text({
			enum: ['presence', 'broadcast', 'postgres_changes'],
		}).notNull(),
	},
);

export const authUid = sql`(select auth.uid())`;
export const realtimeTopic = sql`realtime.topic()`;
```

This allows you to use it in your code, and Drizzle Kit will treat them as existing databases,
using them only as information to connect to other entities

```ts
import { foreignKey, pgPolicy, pgTable, text, uuid } from "drizzle-orm/pg-core";
import { sql } from "drizzle-orm/sql";
import { authenticatedRole, authUsers } from "drizzle-orm/supabase";

export const profiles = pgTable(
  "profiles",
  {
    id: uuid().primaryKey().notNull(),
    email: text().notNull(),
  },
  (table) => [
    foreignKey({
      columns: [table.id],
	  // reference to the auth table from Supabase
      foreignColumns: [authUsers.id],
      name: "profiles_id_fk",
    }).onDelete("cascade"),
    pgPolicy("authenticated can view all profiles", {
      for: "select",
	  // using predefined role from Supabase
      to: authenticatedRole,
      using: sql`true`,
    }),
  ]
);
```

Let's check an example of adding a policy to a table that exists in `Supabase`

```ts
import { sql } from "drizzle-orm";
import { pgPolicy } from "drizzle-orm/pg-core";
import { authenticatedRole, realtimeMessages } from "drizzle-orm/supabase";

export const policy = pgPolicy("authenticated role insert policy", {
  for: "insert",
  to: authenticatedRole,
  using: sql``,
}).link(realtimeMessages);
```

We also have a great example showcasing how to use Drizzle RLS with Supabase and how to make actual queries with it. 
It also includes a great wrapper, `createDrizzle`, that can handle all the transactional work with Supabase for you. 
In upcoming releases, it will be moved to drizzle-orm/supabase, allowing you to use it natively

Please check [Drizzle SupaSecureSlack repo](https://github.com/rphlmr/drizzle-supabase-rls)

Here is an example of an implementation from this repository
```ts
type SupabaseToken = {
  iss?: string;
  sub?: string;
  aud?: string[] | string;
  exp?: number;
  nbf?: number;
  iat?: number;
  jti?: string;
  role?: string;
};

export function createDrizzle(token: SupabaseToken, { admin, client }: { admin: PgDatabase<any>; client: PgDatabase<any> }) {
  return {
    admin,
    rls: (async (transaction, ...rest) => {
      return await client.transaction(async (tx) => {
        // Supabase exposes auth.uid() and auth.jwt()
        // https://supabase.com/docs/guides/database/postgres/row-level-security#helper-functions
        try {
          await tx.execute(sql`
          -- auth.jwt()
          select set_config('request.jwt.claims', '${sql.raw(
            JSON.stringify(token)
          )}', TRUE);
          -- auth.uid()
          select set_config('request.jwt.claim.sub', '${sql.raw(
            token.sub ?? ""
          )}', TRUE);												
          -- set local role
          set local role ${sql.raw(token.role ?? "anon")};
          `);
          return await transaction(tx);
        } finally {
          await tx.execute(sql`
            -- reset
            select set_config('request.jwt.claims', NULL, TRUE);
            select set_config('request.jwt.claim.sub', NULL, TRUE);
            reset role;
            `);
        }
      }, ...rest);
    }) as typeof client.transaction,
  };
}
```

And it can be used as 

```ts
// https://github.com/orgs/supabase/discussions/23224
// Should be secure because we use the access token that is signed, and not the data read directly from the storage
export async function createDrizzleSupabaseClient() {
  const {
    data: { session },
  } = await createClient().auth.getSession();
  return createDrizzle(decode(session?.access_token ?? ""), { admin, client });
}

async function getRooms() {
  const db = await createDrizzleSupabaseClient();
  return db.rls((tx) => tx.select().from(rooms));
}
```


Source: https://orm.drizzle.team/docs/pg/rqb

import Npm from '@mdx/Npm.astro';
import Callout from '@mdx/Callout.astro';
import CodeTabs from '@mdx/CodeTabs.astro';
import CodeTab from '@mdx/CodeTab.astro';
import Section from '@mdx/Section.astro';

# Drizzle Queries

Drizzle ORM is designed to be a thin typed layer on top of SQL. 
We truly believe we've designed the best way to operate an SQL database from TypeScript and it's time to make it better.  
  
Relational queries are meant to provide you with a great developer experience for querying 
nested relational data from an SQL database, avoiding multiple joins and complex data mappings.  

It is an extension to the existing schema definition and query builder. 
You can opt-in to use it based on your needs. 
We've made sure you have both the best-in-class developer experience and performance.  

<Callout type="info" title='Important'>
Inside relational queries, references to a table's columns must go through the callback parameter, not through the imported table object. 
This applies to every clause that accepts a callback — `orderBy`, `where`.`RAW`, `extras` and `subqueries inside extras`. 
The callback exposes the aliased table for the current query scope, which is required for correct SQL generation in nested or self-referential queries.

<Callout type="error" title='❌' collapsed="Example">
```ts
await db.query.posts.findMany({
  orderBy: sql`${posts.id} asc`, // <- ❌ direct table usage
  with: {
    comments: {
      orderBy: sql`${comments.id} desc`, // <- ❌ direct table usage
    },
  },
});
```
```ts
await db.query.users.findMany({
  where: {
    RAW: sql`LOWER(${users.name}) LIKE 'john%'`, // <- ❌ direct table usage
  },
});
```
```ts
await db.query.users.findMany({
  extras: {
    loweredName: sql<string>`lower(${users.name})`, // <- ❌ direct table usage
    totalPostsCount: db.$count(posts, eq(posts.authorId, users.id)),  // <- ❌ direct table usage
  },
});
```
</Callout>
<Callout type="default" title='✅' collapsed="Example">
```ts
await db.query.posts.findMany({
  orderBy: (t) => sql`${t.id} asc`, // <- ✅ callback used
  with: {
    comments: {
      orderBy: (t, { desc }) => desc(t.id), // <- ✅ callback used
    },
  },
});
```
```ts
await db.query.users.findMany({
  where: {
    RAW: (t) => sql`LOWER(${t.name}) LIKE 'john%'`, // <- ✅ callback used
  },
});
```
```ts
await db.query.users.findMany({
  extras: {
    loweredName: (t, { sql }) => sql<string>`lower(${t.name})`, // <- ✅ callback used
    totalPostsCount: (t) => db.$count(posts, eq(posts.authorId, t.id)), // <- ✅ callback used
  },
});
```
</Callout>
</Callout>

<br/>

<Callout type="info" emoji="ℹ️">
	`drizzle` import path depends on the **[database driver](/docs/connect-overview)** you're using.
</Callout>
<CodeTabs items={["index.ts", "schema.ts", "relations.ts"]}>
	<CodeTab>
	```typescript copy
	import { relations } from "./relations";
	import { drizzle } from "drizzle-orm/...";

	const db = drizzle(process.env.DATABASE_URL, { relations });

	const result = await db.query.users.findMany({
	  with: {
	    posts: true,
	  },
	});
	```

	```ts
	[{
		id: 10,
		name: "Dan",
		posts: [
			{
				id: 1,
				content: "SQL is awesome",
				authorId: 10,
			},
			{
				id: 2,
				content: "But check relational queries",
				authorId: 10,
			}
		]
	}]
	```
	</CodeTab>

		```typescript copy
    import * as p from "drizzle-orm/pg-core";
    
    export const posts = p.pgTable("posts", {
      id: p.integer().primaryKey(),
      content: p.text().notNull(),
      authorId: p.integer("author_id").notNull(),
    });
    
    export const users = p.pgTable("users", {
      id: p.integer().primaryKey(),
      name: p.text().notNull(),
    });
	```

	```typescript copy
	import { defineRelations } from "drizzle-orm";
	import { posts, users } from "./schema";

	export const relations = defineRelations({ users, posts }, (r) => ({
      posts: {
        author: r.one.users({
          from: r.posts.authorId,
          to: r.users.id,
        }),
      },
      users: {
        posts: r.many.posts(),
      },
    }));
	```
</CodeTabs>

Relational queries are an extension to Drizzle's original **[query builder](/docs/select)**.
You need to provide all `tables` and `relations` from your schema file/files upon `drizzle()` 
initialization and then just use the `db.query` API.
<Callout type="info" emoji="ℹ️">
	`drizzle` import path depends on the **[database driver](/docs/connect-overview)** you're using.
</Callout>
<CodeTabs items={["index.ts", "schema.ts", "relations.ts"]}>
<CodeTab>
```ts
import { relations } from './relations';
import { drizzle } from 'drizzle-orm/...';

const db = drizzle(process.env.DATABASE_URL,{ relations });

await db.query.users.findMany(...);
```
</CodeTab>
```typescript copy
import { type AnyPgColumn, integer, pgTable, primaryKey, text, timestamp } from 'drizzle-orm/pg-core';

export const users = pgTable('users', {
	id: integer().primaryKey(),
	name: text().notNull(),
	invitedBy: integer('invited_by').references((): AnyPgColumn => users.id),
});

export const groups = pgTable('groups', {
	id: integer().primaryKey(),
	name: text().notNull(),
	description: text(),
});

export const usersToGroups = pgTable('users_to_groups', {
	id: integer().primaryKey(),
	userId: integer('user_id').notNull().references(() => users.id),
	groupId: integer('group_id').notNull().references(() => groups.id),
}, (t) => [
	primaryKey({ columns: [t.userId, t.groupId] })
]);

export const posts = pgTable('posts', {
	id: integer().primaryKey(),
	content: text().notNull(),
	authorId: integer('author_id').references(() => users.id),
	createdAt: timestamp('created_at', { withTimezone: true }).notNull().defaultNow(),
});

export const comments = pgTable('comments', {
	id: integer().primaryKey(),
	content: text().notNull(),
	creator: integer().references(() => users.id),
	postId: integer('post_id').references(() => posts.id),
	createdAt: timestamp('created_at', { withTimezone: true }).notNull().defaultNow(),
});

export const commentLikes = pgTable('comment_likes', {
	id: integer().primaryKey(),
	creator: integer().references(() => users.id),
	commentId: integer('comment_id').references(() => comments.id),
	createdAt: timestamp('created_at', { withTimezone: true }).notNull().defaultNow(),
});
```
```typescript copy
import { defineRelations } from 'drizzle-orm';
import * as schema from './schema';

export const relations = defineRelations(schema, (r) => ({
    users: {
      invitee: r.one.users({
        from: r.users.invitedBy,
        to: r.users.id,
      }),
      groups: r.many.groups({
        from: r.users.id.through(r.usersToGroups.userId),
        to: r.groups.id.through(r.usersToGroups.groupId),
      }),
      posts: r.many.posts(),
    },
    groups: {
      users: r.many.users(),
    },
    posts: {
      author: r.one.users({
        from: r.posts.authorId,
        to: r.users.id,
      }),
      comments: r.many.comments(),
    },
    comments: {
      post: r.one.posts({
        from: r.comments.postId,
        to: r.posts.id,
      }),
      author: r.one.users({
        from: r.comments.creator,
        to: r.users.id,
      }),
      likes: r.many.commentLikes(),
    },
    commentLikes: {
      comment: r.one.comments({
        from: r.commentLikes.commentId,
        to: r.comments.id,
      }),
      author: r.one.users({
        from: r.commentLikes.creator,
        to: r.users.id,
      }),
    },
  })
);
```
</CodeTabs>

Drizzle provides `.findMany()` and `.findFirst()` APIs.
### Find many
<Section>
```typescript copy
const users = await db.query.users.findMany();
```
```ts
// result type
const result: {
	id: number;
	name: string;
	verified: boolean;
	invitedBy: number | null;
}[];
```
</Section>

### Find first
<Callout>
  `.findFirst()` will add `limit 1` to the query.
</Callout>
<Section>
```typescript copy
const user = await db.query.users.findFirst();
```
```ts
// result type
const result: {
	id: number;
	name: string;
	verified: boolean;
	invitedBy: number | null;
};
```
</Section>

### Include relations

`With` operator lets you combine data from multiple related tables and properly aggregate results.

**Getting all posts with comments:**
```typescript copy
const posts = await db.query.posts.findMany({
	with: {
		comments: true,
	},
});
```

**Getting first post with comments:**
```typescript copy
const post = await db.query.posts.findFirst({
	with: {
		comments: true,
	},
});
```

You can chain nested with statements as much as necessary.  
For any nested `with` queries Drizzle will infer types using [Core Type API](/docs/goodies#type-api).
  
**Get all users with posts. Each post should contain a list of comments:**
```typescript copy
const users = await db.query.users.findMany({
	with: {
		posts: {
			with: {
				comments: true,
			},
		},
	},
});
```

### Partial fields select
`columns` parameter lets you include or omit columns you want to get from the database.

<Callout type="info" emoji="ℹ️">
  Drizzle performs partial selects on the query level, no additional data is transferred from the database.

  Keep in mind that **a single SQL statement is outputted by Drizzle.**
</Callout>

**Get all posts with just `id`, `content` and include `comments`:**
```typescript copy
const posts = await db.query.posts.findMany({
	columns: {
		id: true,
		content: true,
	},
	with: {
		comments: true,
	}
});
```

**Get all posts without `content`:**
```typescript copy
const posts = await db.query.posts.findMany({
	columns: {
		content: false,
	},
});
```

<Callout type="info" emoji="ℹ️">
When both `true` and `false` select options are present, all `false` options are ignored.
</Callout>

If you include the `name` field and exclude the `id` field, `id` exclusion will be redundant, 
all fields apart from `name` would be excluded anyways.  
  
**Exclude and Include fields in the same query:**
<Section>
```typescript copy
const users = await db.query.users.findMany({
	columns: {
		name: true,
		id: false //ignored
	},
});
```
```ts
// result type
const users: {
	name: string;
};
```
</Section>

**Only include columns from nested relations:**
<Section>
```typescript copy
const res = await db.query.users.findMany({
	columns: {},
	with: {
		posts: true
	}
});
```
```ts
// result type
const res: {
	posts: {
		id: number,
		text: string
	}
}[];
```
</Section>

### Nested partial fields select
Just like with **[`partial select`](#partial-select)**, you can include or exclude columns of nested relations:
```typescript copy
const posts = await db.query.posts.findMany({
	columns: {
		id: true,
		content: true,
	},
	with: {
		comments: {
			columns: {
				authorId: false
			}
		}
	}
});
```

### Select filters
Just like in our SQL-like query builder, 
relational queries API lets you define filters and conditions with the list of our **[`operators`](/docs/operators)**.  

You can either import them from `drizzle-orm` or use from the callback syntax:
<Section>
```typescript copy
const users = await db.query.users.findMany({
	where: {
		id: 1
	}
});
```
```sql {7}
select
  "d0"."id" as "id",
  "d0"."name" as "name"
from
  "users" as "d0"
where
  "d0"."id" = 1
```
</Section>

Find post with `id=1` and comments that were created before particular date:
```typescript copy
await db.query.posts.findMany({
  where: {
    id: 1,
  },
  with: {
    comments: {
      where: {
        createdAt: { lt: new Date() },
      },
    },
  },
});
```

**List of all filter operators**
```ts
where: {
    OR: [],
    AND: [],
    NOT: {},
    RAW: (table) => sql`${table.id} = 1`,

    // filter by relations
    [relation]: {},

	  // filter by columns
    [column]: {
      OR: [],
      AND: [],
      NOT: {},
      eq: 1,
      ne: 1,
      gt: 1,
      gte: 1,
      lt: 1,
      lte: 1,
      in: [1],
      notIn: [1],
      like: "",
      ilike: "",
      notLike: "",
      notIlike: "",
      isNull: true,
      isNotNull: true,
      arrayOverlaps: [1, 2],
      arrayContained: [1, 2],
      arrayContains: [1, 2]
    },
},
```

**Examples**
<CodeTabs items={["simple eq", "using AND", "using OR", "using NOT", "complex example using RAW"]}>
<CodeTab>
```ts
const response = await db.query.users.findMany({
  where: {
    age: 15,
  },
});
```
```sql {8}
select
  "d0"."id" as "id",
  "d0"."name" as "name",
  "d0"."age" as "age"
from
  "users" as "d0"
where
  "d0"."age" = 15
```
</CodeTab>
<CodeTab>
```ts
const response = await db.query.users.findMany({
  where: {
    age: 15,
    name: 'John'
  },
});
```
```sql {9-10}
select
  "d0"."id" as "id",
  "d0"."name" as "name",
  "d0"."age" as "age"
from
  "users" as "d0"
where
  (
    ("d0"."age" = 15)
    and ("d0"."name" = 'John')
  )
```
</CodeTab>
<CodeTab>
```ts
const response = await db.query.users.findMany({
  where: {
    OR: [
      {
        id: {
          gt: 10,
        },
      },
      {
        name: {
          like: "John%",
        },
      },
    ],
  },
});
```
```sql {9-10}
select
  "d0"."id" as "id",
  "d0"."name" as "name",
  "d0"."age" as "age"
from
  "users" as "d0"
where
  (
    ("d0"."id" > 10)
    or ("d0"."name" like 'John%')
  )
```
</CodeTab>
<CodeTab>
```ts
const response = await db.query.users.findMany({
  where: {
    NOT: {
      id: {
        gt: 10,
      },
    },
    name: {
      like: "John%",
    },
  },
});
```
```sql {9-10}
select
  "d0"."id" as "id",
  "d0"."name" as "name",
  "d0"."age" as "age"
from
  "users" as "d0"
where
  (
    (not ("d0"."id" > 10))
    and ("d0"."name" like 'John%')
  )
```
</CodeTab>
<CodeTab>
```ts
// schema.ts
import { integer, jsonb, pgTable, text, timestamp } from "drizzle-orm/pg-core";
import { sql } from "drizzle-orm";

export const users = pgTable("users", {
  id: integer("id").primaryKey(),
  name: text("name"),
  email: text("email").notNull(),
  age: integer("age"),
  createdAt: timestamp("created_at").defaultNow(),
  lastLogin: timestamp("last_login"),
  subscriptionEnd: timestamp("subscription_end"),
  lastActivity: timestamp("last_activity"),
  preferences: jsonb("preferences"),      // JSON column for user settings/preferences
  interests: text("interests").array(),     // Array column for user interests
});
```
```ts
const response = await db.query.users.findMany({
  where: {
    AND: [
      {
        OR: [
          { RAW: (table) => sql`LOWER(${table.name}) LIKE 'john%'` },
          { name: { ilike: "jane%" } },
        ],
      },
      {
        OR: [
          { RAW: (table) => sql`${table.preferences}->>'theme' = 'dark'` },
          { RAW: (table) => sql`${table.preferences}->>'theme' IS NULL` },
        ],
      },
      { RAW: (table) => sql`${table.age} BETWEEN 25 AND 35` },
    ],
  },
});
```
```sql
SELECT
  "d0"."id" AS "id",
  "d0"."name" AS "name",
  "d0"."email" AS "email",
  "d0"."age" AS "age",
  "d0"."created_at" AS "createdAt",
  "d0"."last_login" AS "lastLogin",
  "d0"."subscription_end" AS "subscriptionEnd",
  "d0"."last_activity" AS "lastActivity",
  "d0"."preferences" AS "preferences",
  "d0"."interests" AS "interests"
FROM
  "users" AS "d0"
WHERE
  (
    (
      (
        (LOWER("d0"."name") LIKE 'john%')
        OR ("d0"."name" ILIKE 'jane%')
      )
    )
    AND (
      (
        ("d0"."preferences" ->> 'theme' = 'dark')
        OR ("d0"."preferences" ->> 'theme' IS NULL)
      )
    )
    AND ("d0"."age" BETWEEN 25 AND 35)
  )
```
</CodeTab>
</CodeTabs>

### Relations Filters

With Drizzle Relations, you can filter not only by the table you're querying but also by any table you include in the query.

**Example:** Get all `users` whose ID>10 and who have at least one post with content starting with "M"
```ts
const usersWithPosts = await db.query.usersTable.findMany({
  where: {
    id: {
      gt: 10
    },
    posts: {
      content: {
        like: 'M%'
      }
    }
  },
});
```

**Example:** Get all `users` with posts, only if user has at least 1 post
```ts
const response = await db.query.users.findMany({
  with: {
    posts: true,
  },
  where: {
    posts: true,
  },
});
```

### Limit & Offset
Drizzle ORM provides `limit` & `offset` API for queries and for the nested entities.
  
**Find 5 posts:**
```typescript copy
await db.query.posts.findMany({
	limit: 5,
});
```

**Find posts and get 3 comments at most:**
```typescript copy
await db.query.posts.findMany({
	with: {
		comments: {
			limit: 3,
		},
	},
});
```

<Callout type="warning" emoji="⚠️">
  `offset` now can be used in with tables as well!
</Callout>
```typescript 
await db.query.posts.findMany({
	limit: 5,
	offset: 2, // correct ✅
	with: {
		comments: {
			offset: 3, // correct ✅
			limit: 3,
		},
	},
});
```

Find posts with comments from the 6th to the 10th post:
```typescript copy
await db.query.posts.findMany({
	with: {
		comments: true,
	},
  limit: 5,
  offset: 5,
});
```

### Order By
Drizzle provides API for ordering in the relational query builder.  

You can use same ordering **[core API](/docs/select#order-by)** or use
`order by` operator from the callback with no imports.  

<Callout title='important'>
When you use multiple `orderBy` statements in the same table, they will be included in the query in the same order in which you added them
</Callout>

<Section>
```typescript copy
await db.query.posts.findMany({
  orderBy: {
    id: "asc",
  },
});
```
</Section>

**Order by `asc` + `desc`:**
```typescript copy
  await db.query.posts.findMany({
    orderBy: { id: "asc" },
    with: {
      comments: {
        orderBy: { id: "desc" },
      },
    },
  });
```

You can also use custom `sql` in order by statement:

```typescript copy
await db.query.posts.findMany({
  orderBy: (t) => sql`${t.id} asc`,
  with: {
    comments: {
      orderBy: (t, { desc }) => desc(t.id),
    },
  },
});
```

### Include custom fields
Relational query API lets you add custom additional fields. 
It's useful when you need to retrieve data and apply additional functions to it.
<Callout type="warning" emoji="⚠️">
	As of now aggregations are not supported in `extras`, please use **[`core queries`](/docs/select)** for that.
</Callout>

<Section>
```typescript copy {5}
import { sql } from 'drizzle-orm';

await db.query.users.findMany({
  extras: {
    loweredName: (table) => sql`lower(${table.name})`,
  },
});
```
```typescript copy {3}
await db.query.users.findMany({
	extras: {
		loweredName: (users, { sql }) => sql`lower(${users.name})`,
	},
})
```
</Section>

`lowerName` as a key will be included to all fields in returned object.

<Callout type="warning" emoji="⚠️">
  If you will specify `.as("<alias>")` for any extras field - drizzle will ignore it
</Callout>

To retrieve all users with groups, but with the fullName field included (which is a concatenation of firstName and lastName), 
you can use the following query with the Drizzle relational query builder.

<Section>
```typescript copy
const res = await db.query.users.findMany({
	extras: {
		fullName: (users, { sql }) => sql<string>`concat(${users.name}, " ", ${users.name})`,
	},
	with: {
		groups: true,
	},
});
```
```ts
// result type
const res: {
    id: number;
    name: string;
    age: number | null;
    invitedBy: number | null;
    fullName: string;
    groups: {
        id: number;
        name: string;
        description: string | null;
    }[];
}[]
```
</Section>

To retrieve all posts with comments and add an additional field to calculate the size of the post content and the size of each comment content:
<Section>
```typescript copy
const res = await db.query.posts.findMany({
	extras: {
		contentLength: (table, { sql }) => sql<number>`length(${table.content})`,
	},
	with: {
		comments: {
			extras: {
				commentSize: (table, { sql }) => sql<number>`length(${table.content})`,
			},
		},
	},
});
```
```ts
// result type
const res: {
    id: number;
    content: string;
    authorId: number | null;
    createdAt: Date;
    contentLength: number;
    comments: {
        id: number;
        content: string;
        createdAt: Date;
        creator: number | null;
        postId: number | null;
        commentSize: number;
    }[];
}[]
```
</Section>

### Include subqueries

You can also use subqueries within Relational Queries to leverage the power of custom SQL syntax

**Get users with posts and total posts count for each user**
```ts
import { posts } from './schema';
import { eq } from 'drizzle-orm';

await db.query.users.findMany({
  with: {
    posts: true
  },
  extras: {
    totalPostsCount: (table) => db.$count(posts, eq(posts.authorId, table.id)),
  }
});
```
```sql
SELECT
  "d0"."id" AS "id",
  "d0"."name" AS "name",
  "d0"."age" AS "age",
  "d0"."invited_by" AS "invitedBy",
  (
    (
      SELECT
        count(*)
      FROM
        "posts"
      WHERE
        "posts"."author_id" = "d0"."id"
    )
  ) AS "totalPostsCount",
  "posts"."r" AS "posts"
FROM
  "users" AS "d0"
  LEFT JOIN LATERAL (
    SELECT
      coalesce(json_agg(row_to_json("t".*)), '[]') AS "r"
    FROM
      (
        SELECT
          "d1"."id" AS "id",
          "d1"."content" AS "content",
          "d1"."author_id" AS "authorId",
          "d1"."created_at"::text AS "createdAt"
        FROM
          "posts" AS "d1"
        WHERE
          "d0"."id" = "d1"."author_id"
      ) AS "t"
  ) AS "posts" ON TRUE
```

### Prepared statements
Prepared statements are designed to massively improve query performance — [see here.](/docs/perf-queries)

In this section, you can learn how to define placeholders and execute prepared statements 
using the Drizzle relational query builder.

##### **Placeholder in `where`**

<Section>
```ts copy
const prepared = db.query.users.findMany({
    where: { id: { eq: sql.placeholder("id") } },
    with: {
      posts: {
        where: { id: 1 },
      },
    },
}).prepare("query_name");

const usersWithPosts = await prepared.execute({ id: 1 });
```
</Section>

##### **Placeholder in `limit`**

<Section>
```ts copy
const prepared = db.query.users.findMany({
    with: {
      posts: {
        limit: sql.placeholder("limit"),
      },
    },
  }).prepare("query_name");

const usersWithPosts = await prepared.execute({ limit: 1 });
```
</Section>

##### **Placeholder in `offset`**

<Section>
```ts copy
const prepared = db.query.users.findMany({
	offset: sql.placeholder('offset'),
	with: {
		posts: true,
	},
}).prepare('query_name');

const usersWithPosts = await prepared.execute({ offset: 1 });
```
</Section>

##### **Multiple placeholders**

<Section>
```ts copy
const prepared = db.query.users.findMany({
    limit: sql.placeholder("uLimit"),
    offset: sql.placeholder("uOffset"),
    where: {
      OR: [{ id: { eq: sql.placeholder("id") } }, { id: 3 }],
    },
    with: {
      posts: {
        where: { id: { eq: sql.placeholder("pid") } },
        limit: sql.placeholder("pLimit"),
      },
    },
}).prepare("query_name");

const usersWithPosts = await prepared.execute({ pLimit: 1, uLimit: 3, uOffset: 1, id: 2, pid: 6 });
```
</Section>


Source: https://orm.drizzle.team/docs/pg/schemas

import Section from '@mdx/Section.astro';
import Callout from '@mdx/Callout.astro';

# Table schemas

If you declare an entity within a schema, query builder will prepend schema names in queries:<br/>
`select * from "schema"."users"`

<Section>
    ```ts copy {3,5,7}
    import { serial, text, pgSchema } from "drizzle-orm/pg-core";

    export const mySchema = pgSchema("my_schema");

    export const colors = mySchema.enum('colors', ['red', 'green', 'blue']);

    export const mySchemaUsers = mySchema.table('users', {
      id: serial('id').primaryKey(),
      name: text('name'),
      color: colors('color').default('red'),
    });

    
    ```
    ```sql
    CREATE SCHEMA "my_schema";

    CREATE TYPE "my_schema"."colors" AS ENUM ('red', 'green', 'blue');

    CREATE TABLE "my_schema"."users" (
      "id" serial PRIMARY KEY,
      "name" text,
      "color" "my_schema"."colors" DEFAULT 'red'
    );
    ```
    </Section>

{/* TODO: ??? example > **Warning**
> If you will have tables with same names in different schemas then drizzle will respond with `never[]` error in result types and error from database
>
> In this case you may use [alias syntax](./joins#join-aliases-and-self-joins) */}


Source: https://orm.drizzle.team/docs/pg/seed-overview

import Npm from "@mdx/Npm.astro";
import Callout from '@mdx/Callout.astro';
import CodeTabs from "@mdx/CodeTabs.astro";
import Section from "@mdx/Section.astro";
import Tab from "@mdx/Tab.astro";
import Tabs from "@mdx/Tabs.astro";

# Drizzle Seed

`drizzle-seed` is a TypeScript library that helps you generate deterministic, yet realistic,
fake data to populate your database. By leveraging a seedable pseudorandom number generator (pRNG),
it ensures that the data you generate is consistent and reproducible across different runs.
This is especially useful for testing, development, and debugging purposes.

#### What is Deterministic Data Generation?

Deterministic data generation means that the same input will always produce the same output.
In the context of `drizzle-seed`, when you initialize the library with the same seed number,
it will generate the same sequence of fake data every time. This allows for predictable and repeatable data sets.

#### Pseudorandom Number Generator (pRNG)

A pseudorandom number generator is an algorithm that produces a sequence of numbers
that approximates the properties of random numbers. However, because it's based on an initial value
called a seed, you can control its randomness. By using the same seed, the pRNG will produce the
same sequence of numbers, making your data generation process reproducible.

#### Benefits of Using a pRNG:

- Consistency: Ensures that your tests run on the same data every time.
- Debugging: Makes it easier to reproduce and fix bugs by providing a consistent data set.
- Collaboration: Team members can share seed numbers to work with the same data sets.

With drizzle-seed, you get the best of both worlds: the ability to generate realistic fake data and the control to reproduce it whenever needed.

## Installation

<Npm>drizzle-seed</Npm>

## Basic Usage

In this example we will create 10 users with random names and ids

```ts {12}
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

```ts
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

```ts
await seed(db, schema, { seed: 12345 });
```

## Reset database

With `drizzle-seed`, you can easily reset your database and seed it with new values, for example, in your test suites

```ts
// path to a file with schema you want to reset
import * as schema from "./schema.ts";
import { reset } from "drizzle-seed";

async function main() {
  const db = drizzle(process.env.DATABASE_URL!);
  await reset(db, schema);
}

main();
```

Different dialects will have different strategies for database resetting

For PostgreSQL, the `drizzle-seed` package will generate `TRUNCATE` statements with the `CASCADE` option to 
ensure that all tables are empty after running the reset function

```sql
TRUNCATE tableName1, tableName2, ... CASCADE;
```

## Refinements

In case you need to change the behavior of the seed generator functions that `drizzle-seed` uses by default, you can specify your own implementation and even use your own list of values for the seeding process

`.refine` is a callback that receives a list of all available generator functions from `drizzle-seed`. It should return an object with keys representing the tables you want to refine, defining their behavior as needed. 
Each table can specify several properties to simplify seeding your database:

<rem025 />

- `columns`: Refine the default behavior of each column by specifying the required generator function, or exclude the column from seeding by specifying `false`.
- `count`: Specify the number of rows to insert into the database. By default, it's 10. If a global count is defined in the `seed()` options, the count defined here will override it for this specific table.
- `with`: Define how many referenced entities to create for each parent table if you want to generate associated entities.

<Callout title='info'>
You can also specify a weighted random distribution for the number of referenced values you want to create. For details on this API, you can refer to [Weighted Random docs](#weighted-random) docs section
</Callout>

**API**
```ts
await seed(db, schema).refine((f) => ({
  users: {
    columns: {},
    count: 10,
    with: {
        posts: 10
    }
  },
}));
```

Let's check a few examples with an explanation of what will happen:

```ts filename='schema.ts'
import { pgTable, integer, text } from "drizzle-orm/pg-core";

export const users = pgTable("users", {
  id: integer().primaryKey(),
  name: text().notNull(),
});

export const posts = pgTable("posts", {
  id: integer().primaryKey(),
  description: text(),
  userId: integer().references(() => users.id),
});
```

**Example 1**: Seed only the `users` table with 20 entities and with refined seed logic for the `name` column
```ts filename='index.ts'
import { drizzle } from "drizzle-orm/node-postgres";
import { seed } from "drizzle-seed";
import * as schema from './schema.ts'

async function main() {
  const db = drizzle(process.env.DATABASE_URL!);

  await seed(db, { users: schema.users }).refine((f) => ({
    users: {
        columns: {
            name: f.fullName(),
        },
        count: 20
    }
  }));
}

main();
```

**Example 2**: Seed only the `users` table, excluding the `name` column from seeding
```ts filename='index.ts'
import { drizzle } from "drizzle-orm/node-postgres";
import { seed } from "drizzle-seed";
import * as schema from './schema.ts'

async function main() {
  const db = drizzle(process.env.DATABASE_URL!);

  await seed(db, { users: schema.users }).refine((f) => ({
    users: {
        columns: {
            name: false, // the name column will not be seeded, allowing the database to use its default value.
        }
    }
  }));
}

main();
```

**Example 3**: Seed the `users` table with 20 entities and add 10 `posts` for each `user` by seeding the `posts` table and creating a reference from `posts` to `users`
```ts filename='index.ts'
import { drizzle } from "drizzle-orm/node-postgres";
import { seed } from "drizzle-seed";
import * as schema from './schema.ts'

async function main() {
  const db = drizzle(process.env.DATABASE_URL!);

  await seed(db, schema).refine((f) => ({
    users: {
        count: 20,
        with: {
            posts: 10
        }
    }
  }));
}

main();
```

**Example 4**: Seed the `users` table with 5 entities and populate the database with 100 `posts` without connecting them to the `users` entities. Refine `id` generation for `users` so 
that it will give any int from `10000` to `20000` and remains unique, and refine `posts` to retrieve values from a self-defined array
```ts filename='index.ts'
import { drizzle } from "drizzle-orm/node-postgres";
import { seed } from "drizzle-seed";
import * as schema from './schema.ts'

async function main() {
  const db = drizzle(process.env.DATABASE_URL!);

  await seed(db, schema).refine((f) => ({
    users: {
        count: 5,
        columns: {
            id: f.int({
              minValue: 10000,
              maxValue: 20000,
              isUnique: true,
            }),
        }
    },
    posts: {
        count: 100,
        columns: {
            description: f.valuesFromArray({
            values: [
                "The sun set behind the mountains, painting the sky in hues of orange and purple", 
                "I can't believe how good this homemade pizza turned out!", 
                "Sometimes, all you need is a good book and a quiet corner.", 
                "Who else thinks rainy days are perfect for binge-watching old movies?", 
                "Tried a new hiking trail today and found the most amazing waterfall!",
                // ...
            ],
          })
        }
    }
  }));
}

main();
```

<Callout type='warning'>
There are many more possibilities that we will define in these docs, but for now, you can explore a few sections in this documentation. Check the [Generators](/docs/seed-functions) section to get familiar with all the available generator functions you can use.

A particularly great feature is the ability to use weighted randomization, both for generator values created for a column and for determining the number of related entities that can be generated by `drizzle-seed`.

Please check [Weighted Random docs](#weighted-random) for more info.
</Callout>

## Weighted Random

There may be cases where you need to use multiple datasets with a different priority that should be inserted into your database during the seed stage. For such cases, drizzle-seed provides an API called weighted random

The Drizzle Seed package has a few places where weighted random can be used:

- Columns inside each table refinements
- The `with` property, determining the amount of related entities to be created

Let's check an example for both:

```ts filename="schema.ts"
import { pgTable, integer, text, varchar, doublePrecision } from "drizzle-orm/pg-core";

export const orders = pgTable(
  "orders",
  {
    id: integer().primaryKey(),
    name: text().notNull(),
    quantityPerUnit: varchar().notNull(),
    unitPrice: doublePrecision().notNull(),
    unitsInStock: integer().notNull(),
    unitsOnOrder: integer().notNull(),
    reorderLevel: integer().notNull(),
    discontinued: integer().notNull(),
  }
);

export const details = pgTable(
  "details",
  {
    unitPrice: doublePrecision().notNull(),
    quantity: integer().notNull(),
    discount: doublePrecision().notNull(),

    orderId: integer()
      .notNull()
      .references(() => orders.id, { onDelete: "cascade" }),
  }
);
```

**Example 1**: Refine the `unitPrice` generation logic to generate `5000` random prices, with a 30% chance of prices between 10-100 and a 70% chance of prices between 100-300

```ts filename="index.ts"
import { drizzle } from "drizzle-orm/node-postgres";
import { seed } from "drizzle-seed";
import * as schema from './schema.ts'

async function main() {
  const db = drizzle(process.env.DATABASE_URL!);

  await seed(db, schema).refine((f) => ({
    orders: {
       count: 5000,
       columns: {
           unitPrice: f.weightedRandom(
               [
                   {
                       weight: 0.3,
                       value: funcs.int({ minValue: 10, maxValue: 100 })
                   },
                   {
                       weight: 0.7,
                       value: funcs.number({ minValue: 100, maxValue: 300, precision: 100 })
                   }
               ]
           ),
       }
    }
  }));
}

main();
```

**Example 2**: For each order, generate 1 to 3 details with a 60% chance, 5 to 7 details with a 30% chance, and 8 to 10 details with a 10% chance

```ts filename="index.ts"
import { drizzle } from "drizzle-orm/node-postgres";
import { seed } from "drizzle-seed";
import * as schema from './schema.ts'

async function main() {
  const db = drizzle(process.env.DATABASE_URL!);

  await seed(db, schema).refine((f) => ({
    orders: {
       with: {
           details:
               [
                   { weight: 0.6, count: [1, 2, 3] },
                   { weight: 0.3, count: [5, 6, 7] },
                   { weight: 0.1, count: [8, 9, 10] },
               ]
       }
    }
  }));
}

main();
```

## Complex example

<CodeTabs items={["main.ts", "schema.ts"]}>
<Section>
```ts
import { seed } from "drizzle-seed";
import * as schema from "./schema.ts";

const main = async () => {
    const titlesOfCourtesy = ["Ms.", "Mrs.", "Dr."];
    const unitsOnOrders = [0, 10, 20, 30, 50, 60, 70, 80, 100];
    const reorderLevels = [0, 5, 10, 15, 20, 25, 30];
    const quantityPerUnit = [
        "100 - 100 g pieces",
        "100 - 250 g bags",
        "10 - 200 g glasses",
        "10 - 4 oz boxes",
        "10 - 500 g pkgs.",
        "10 - 500 g pkgs."
    ];
    const discounts = [0.05, 0.15, 0.2, 0.25];

    await seed(db, schema).refine((funcs) => ({
        customers: {
            count: 10000,
            columns: {
                companyName: funcs.companyName(),
                contactName: funcs.fullName(),
                contactTitle: funcs.jobTitle(),
                address: funcs.streetAddress(),
                city: funcs.city(),
                postalCode: funcs.postcode(),
                region: funcs.state(),
                country: funcs.country(),
                phone: funcs.phoneNumber({ template: "(###) ###-####" }),
                fax: funcs.phoneNumber({ template: "(###) ###-####" })
            }
        },
        employees: {
            count: 200,
            columns: {
                firstName: funcs.firstName(),
                lastName: funcs.lastName(),
                title: funcs.jobTitle(),
                titleOfCourtesy: funcs.valuesFromArray({ values: titlesOfCourtesy }),
                birthDate: funcs.date({ minDate: "2010-12-31", maxDate: "2010-12-31" }),
                hireDate: funcs.date({ minDate: "2010-12-31", maxDate: "2024-08-26" }),
                address: funcs.streetAddress(),
                city: funcs.city(),
                postalCode: funcs.postcode(),
                country: funcs.country(),
                homePhone: funcs.phoneNumber({ template: "(###) ###-####" }),
                extension: funcs.int({ minValue: 428, maxValue: 5467 }),
                notes: funcs.loremIpsum()
            }
        },
        orders: {
            count: 50000,
            columns: {
                shipVia: funcs.int({ minValue: 1, maxValue: 3 }),
                freight: funcs.number({ minValue: 0, maxValue: 1000, precision: 100 }),
                shipName: funcs.streetAddress(),
                shipCity: funcs.city(),
                shipRegion: funcs.state(),
                shipPostalCode: funcs.postcode(),
                shipCountry: funcs.country()
            },
            with: {
                details:
                    [
                        { weight: 0.6, count: [1, 2, 3, 4] },
                        { weight: 0.2, count: [5, 6, 7, 8, 9, 10] },
                        { weight: 0.15, count: [11, 12, 13, 14, 15, 16, 17] },
                        { weight: 0.05, count: [18, 19, 20, 21, 22, 23, 24, 25] },
                    ]
            }
        },
        suppliers: {
            count: 1000,
            columns: {
                companyName: funcs.companyName(),
                contactName: funcs.fullName(),
                contactTitle: funcs.jobTitle(),
                address: funcs.streetAddress(),
                city: funcs.city(),
                postalCode: funcs.postcode(),
                region: funcs.state(),
                country: funcs.country(),
                phone: funcs.phoneNumber({ template: "(###) ###-####" })
            }
        },
        products: {
            count: 5000,
            columns: {
                name: funcs.companyName(),
                quantityPerUnit: funcs.valuesFromArray({ values: quantityPerUnit }),
                unitPrice: funcs.weightedRandom(
                    [
                        {
                            weight: 0.5,
                            value: funcs.int({ minValue: 3, maxValue: 300 })
                        },
                        {
                            weight: 0.5,
                            value: funcs.number({ minValue: 3, maxValue: 300, precision: 100 })
                        }
                    ]
                ),
                unitsInStock: funcs.int({ minValue: 0, maxValue: 125 }),
                unitsOnOrder: funcs.valuesFromArray({ values: unitsOnOrders }),
                reorderLevel: funcs.valuesFromArray({ values: reorderLevels }),
                discontinued: funcs.int({ minValue: 0, maxValue: 1 })
            }
        },
        details: {
            columns: {
                unitPrice: funcs.number({ minValue: 10, maxValue: 130 }),
                quantity: funcs.int({ minValue: 1, maxValue: 130 }),
                discount: funcs.weightedRandom(
                    [
                        { weight: 0.5, value: funcs.valuesFromArray({ values: discounts }) },
                        { weight: 0.5, value: funcs.default({ defaultValue: 0 }) }
                    ]
                )
            }
        }
    }));
}

main();

```
</Section>
<Section>
```ts
import type { AnyPgColumn } from "drizzle-orm/pg-core";
import { integer, numeric, pgTable, text, timestamp, varchar } from "drizzle-orm/pg-core";

export const customers = pgTable('customer', {
	id: varchar({ length: 256 }).primaryKey(),
	companyName: text().notNull(),
	contactName: text().notNull(),
	contactTitle: text().notNull(),
	address: text().notNull(),
	city: text().notNull(),
	postalCode: text(),
	region: text(),
	country: text().notNull(),
	phone: text().notNull(),
	fax: text(),
});

export const employees = pgTable(
	'employee',
	{
		id: integer().primaryKey(),
		lastName: text().notNull(),
		firstName: text(),
		title: text().notNull(),
		titleOfCourtesy: text().notNull(),
		birthDate: timestamp().notNull(),
		hireDate: timestamp().notNull(),
		address: text().notNull(),
		city: text().notNull(),
		postalCode: text().notNull(),
		country: text().notNull(),
		homePhone: text().notNull(),
		extension: integer().notNull(),
		notes: text().notNull(),
		reportsTo: integer().references((): AnyPgColumn => employees.id),
		photoPath: text(),
	},
);

export const orders = pgTable('order', {
	id: integer().primaryKey(),
	orderDate: timestamp().notNull(),
	requiredDate: timestamp().notNull(),
	shippedDate: timestamp(),
	shipVia: integer().notNull(),
	freight: numeric().notNull(),
	shipName: text().notNull(),
	shipCity: text().notNull(),
	shipRegion: text(),
	shipPostalCode: text(),
	shipCountry: text().notNull(),

	customerId: text().notNull().references(() => customers.id, { onDelete: 'cascade' }),

	employeeId: integer().notNull().references(() => employees.id, { onDelete: 'cascade' }),
});

export const suppliers = pgTable('supplier', {
	id: integer().primaryKey(),
	companyName: text().notNull(),
	contactName: text().notNull(),
	contactTitle: text().notNull(),
	address: text().notNull(),
	city: text().notNull(),
	region: text(),
	postalCode: text().notNull(),
	country: text().notNull(),
	phone: text().notNull(),
});

export const products = pgTable('product', {
	id: integer().primaryKey(),
	name: text().notNull(),
	quantityPerUnit: text().notNull(),
	unitPrice: numeric().notNull(),
	unitsInStock: integer().notNull(),
	unitsOnOrder: integer().notNull(),
	reorderLevel: integer().notNull(),
	discontinued: integer().notNull(),

	supplierId: integer().notNull().references(() => suppliers.id, { onDelete: 'cascade' }),
});

export const details = pgTable('order_detail', {
	unitPrice: numeric().notNull(),
	quantity: integer().notNull(),
	discount: numeric().notNull(),

	orderId: integer().notNull().references(() => orders.id, { onDelete: 'cascade' }),

	productId: integer().notNull().references(() => products.id, { onDelete: 'cascade' }),
});

```
</Section>
</CodeTabs>

## Limitations

#### Types limitations for `with`

Due to certain TypeScript limitations and the current API in Drizzle, it is not possible to properly infer references between tables, especially when circular dependencies between tables exist.

This means the `with` option will display all tables in the schema, and you will need to manually select the one that has a one-to-many relationship

<Callout title='warning'>
The `with` option works for one-to-many relationships. For example, if you have one `user` and many `posts`, you can use users `with` posts, but you cannot use posts `with` users
</Callout>

#### Composite unique constraints
- Seeding is not supported when two composite unique constraints share a column:
```ts
const composite = pgTable(
  "composite_example",
  {
    id: integer("id").notNull(),
    name: text("name").notNull(),
    slug: text("slug").notNull(),
  },
  (t) => [
    unique("custom_name").on(t.id, t.name),
    unique("custom_name1").on(t.name, t.slug),
  ]
);
```
This is allowed, however, if one of the constraints is a single-column unique constraint:
```ts
unique("custom_name1").on(t.name);
```
- You can’t use a generator that doesn’t expose an `isUnique` option in its config, unless it’s one of the always-unique generators: `intPrimaryKey`, `email`, `phoneNumber`, or `uuid`.

Source: https://orm.drizzle.team/docs/pg/seed-versioning

import Callout from "@mdx/Callout.astro";
import TableWrapper from "@mdx/TableWrapper.astro";

# Versioning

`drizzle-seed` uses versioning to manage outputs for static and dynamic data. To ensure true 
determinism, ensure that values remain unchanged when using the same `seed` number. If changes are made to 
static data sources or dynamic data generation logic, the version will be updated, allowing
you to choose between sticking with the previous version or using the latest.

You can upgrade to the latest `drizzle-seed` version for new features, such as additional
generators, while maintaining deterministic outputs with a previous version if needed. This
is particularly useful when you need to rely on existing deterministic data while accessing new functionality.

```ts
await seed(db, schema, { version: '2' });
```

## History
<TableWrapper>
|          api version  |   npm version    |     Changed generators                    |
|  :--------------      | :--------------  | :-------------                            |
|       `v1`            | `0.1.1`          |                                           |
|       `v2`	          | `0.2.1`          |`string()`, `interval({ isUnique: true })` |
|       `v3`            | `0.4.0`          |`hash generating function`    			       |
|       `v4 (LTS) `     | `1.0.0-beta.8`   |`uuid` 								                     |
</TableWrapper>

<Callout collapsed="How it works under the hood?">
> This is not an actual API change; it is just an example of how we will proceed with `drizzle-seed` versioning.

For example, `lastName` generator was changed, and new version, `V2`, of this generator became available.

Later, `firstName` generator was changed, making `V3` version of this generator available.

|                  |       `V1`       |      `V2`       |   `V3(latest)`   |
| :--------------: | :--------------: | :-------------: | :--------------: |
| **LastNameGen**  | `LastNameGenV1`  | `LastNameGenV2` |                  |
| **FirstNameGen** | `FirstNameGenV1` |                 | `FirstNameGenV3` |

##### Use the `firstName` generator of version 3 and the `lastName` generator of version 2
```ts
await seed(db, schema);
```

If you are not ready to use latest generator version right away, you can specify max version to use

##### Use the `firstName` generator of version 1 and the `lastName` generator of version 2
```ts
await seed(db, schema, { version: '2' });
```

##### Use the `firstName` generator of version 1 and the `lastName` generator of version 1.
```ts
await seed(db, schema, { version: '1' });
```

</Callout>

## Version 2
#### Unique `interval` generator was changed

<Callout title='Reason for upgrade'>
An older version of the generator could produce intervals like `1 minute 60 seconds` and `2 minutes 0 seconds`, treating them as distinct intervals.
However, when the `1 minute 60 seconds` interval is inserted into a PostgreSQL database, it is automatically converted to `2 minutes 0 seconds`. As a result, attempting to insert the `2 minutes 0 seconds` interval into a unique column afterwards will cause an error
</Callout>

You will be affected, if your table includes a unique column of type `interval`:

```ts
import { drizzle } from "drizzle-orm/node-postgres";
import { pgTable, interval } from "drizzle-orm/pg-core";
import { seed } from "drizzle-seed";

const intervals = pgTable("intervals", {
    interval: interval().unique()
});

async function main() {
  const db = drizzle(process.env.DATABASE_URL!);

  await seed(db, { intervals });
}

main();
```

You will be affected, if you use the unique `interval` generator in your seeding script, as shown in the script below:

```ts
import { drizzle } from "drizzle-orm/node-postgres";
import { pgTable, interval, char, varchar, text } from "drizzle-orm/pg-core";
import { seed } from "drizzle-seed";

const intervals = pgTable("intervals", {
    interval: interval().unique(),
    interval1: interval(),
    interval2: char({ length: 256 }).unique(),
    interval3: char({ length: 256 }),
    interval4: varchar().unique(),
    interval5: varchar(),
    interval6: text().unique(),
    interval7: text(),
});

async function main() {
  const db = drizzle(process.env.DATABASE_URL!);

  await seed(db, { intervals }).refine((f) => ({
    intervals: {
        columns: {
            interval: f.interval({ isUnique: true }),
            interval1: f.interval({ isUnique: true }),
            interval2: f.interval({ isUnique: true }),
            interval3: f.interval({ isUnique: true }),
            interval4: f.interval({ isUnique: true }),
            interval5: f.interval({ isUnique: true }),
            interval6: f.interval({ isUnique: true }),
            interval7: f.interval({ isUnique: true }),
        }
    }
  }));
}

main();
```

#### `string` generators were changed: both non-unique and unique

<Callout title='Reason to upgrade'>
Ability to generate a unique string based on the length of the text column (e.g., `varchar(20)`)
</Callout>

You will be affected, if your table includes a column of a text-like type with a maximum length parameter or a unique column of a text-like type:

```ts
import { drizzle } from "drizzle-orm/node-postgres";
import { pgTable, char, varchar, text } from "drizzle-orm/pg-core";
import { seed } from "drizzle-seed";

const strings = pgTable("strings", {
    string2: char({ length: 256 }).unique(),
    string3: char({ length: 256 }),
    string4: varchar().unique(),
    string5: varchar({ length: 256 }).unique(),
    string6: varchar({ length: 256 }),
    string7: text().unique(),
});

async function main() {
  const db = drizzle(process.env.DATABASE_URL!);

  await seed(db, { strings });
}

main();
```

You will be affected, if you use the `string` generator in your seeding script, as shown in the script below:

```ts
import { drizzle } from "drizzle-orm/node-postgres";
import { pgTable, char, varchar, text } from "drizzle-orm/pg-core";
import { seed } from "drizzle-seed";

const strings = pgTable("strings", {
    string1: char({ length: 256 }).unique(),
    string2: char({ length: 256 }),
    string3: char({ length: 256 }),
    string4: varchar(),
    string5: varchar().unique(),
    string6: varchar({ length: 256 }).unique(),
    string7: varchar({ length: 256 }),
    string8: varchar({ length: 256 }),
    string9: text().unique(),
    string10: text(),
});

async function main() {
  const db = drizzle(process.env.DATABASE_URL!);

  await seed(db, { strings }).refine((f) => ({
    strings: {
        columns: {
            string1: f.string({ isUnique: true }),
            string2: f.string(),
            string3: f.string({ isUnique: true }),
            string4: f.string({ isUnique: true }),
            string5: f.string({ isUnique: true }),
            string6: f.string({ isUnique: true }),
            string7: f.string(),
            string8: f.string({ isUnique: true }),
            string9: f.string({ isUnique: true }),
            string10: f.string({ isUnique: true }),
        }
    }
  }));
}

main();
```

## Version 3
#### `hash generating function was changed`

<Callout title='Reason to upgrade'>
The previous version of the hash generating function generated different hashes depending on whether Bun or Node.js was used, and hashes also varied across versions of Node.js.

The new hash generating function will generate the same hash regardless of the version of Node.js or Bun, resulting in deterministic data generation across all versions.
</Callout>

All generators will output different values compared to the previous version, even with the same seed number.

**Usage**
```ts
await seed(db, schema);
// or explicit
await seed(db, schema, { version: '3' });
```

**Switch to the old version**

The previous version of hash generating function is v1.
```ts
await seed(db, schema, { version: '1' });
```
To use the v2 generators while maintaining the v1 hash generating function:
```ts
await seed(db, schema, { version: '2' });
```

## Version 4
#### `uuid` generator was changed

<Callout title='Reason to upgrade'>
UUID values generated by the old version of the `uuid` generator fail Zod’s v4 UUID validation.

example
```ts
import { createSelectSchema } from 'drizzle-zod';
import { seed } from 'drizzle-seed';

await seed(db, { uuidTest: schema.uuidTest }, { count: 1 }).refine((funcs) => ({
		uuidTest: {
			columns: {
				col1: funcs.uuid()
			}
		}
	})
);

const uuidSelectSchema = createSelectSchema(schema.uuidTest);
const res = await db.select().from(schema.uuidTest);
// the line below will throw an error when using old version of uuid generator
uuidSelectSchema.parse(res[0]);
```
</Callout>

**Usage**
```ts
await seed(db, schema);
// or explicit
await seed(db, schema, { version: '4' });
```

**Switch to the old version**

The previous version of `uuid` generator is v1.
```ts
await seed(db, schema, { version: '1' });
```
To use the v2 generators while maintaining the v1 `uuid` generator:
```ts
await seed(db, schema, { version: '2' });
```
To use the v3 generators while maintaining the v1 `uuid` generator:
```ts
await seed(db, schema, { version: '3' });
```


Source: https://orm.drizzle.team/docs/pg/select

import CodeTabs from '@mdx/CodeTabs.astro';
import Callout from '@mdx/Callout.astro';
import Section from '@mdx/Section.astro';
import $count from '@mdx/$count-pg.mdx';

# SQL Select
Drizzle provides you the most SQL-like way to fetch data from your database, while remaining type-safe and composable.
It natively supports mostly every query feature and capability of every dialect,
and whatever it doesn't support yet, can be added by the user with the powerful [sql](/docs/sql) operator.

For the following examples, let's assume you have a `users` table defined like this:

```typescript
import { pgTable, serial, text, integer } from 'drizzle-orm/pg-core';

export const users = pgTable('users', {
  id: serial().primaryKey(),
  name: text().notNull(),
  age: integer(),
});
```

### Basic select
Select all rows from a table including all columns:

<Section>
```typescript
const result = await db.select().from(users);
/*
  {
    id: number;
    name: string;
    age: number | null;
  }[]
*/
```
```sql
select "id", "name", "age" from "users";
```
</Section>

Notice that the result type is inferred automatically based on the table definition, including columns nullability.

<Callout type="info">
Drizzle always explicitly lists columns in the `select` clause instead of using `select *`.<br />
This is required internally to guarantee the fields order in the query result, and is also generally considered a good practice.
</Callout>

### Partial select
In some cases, you might want to select only a subset of columns from a table.
You can do that by providing a selection object to the `.select()` method:
<Section>
```typescript copy
const result = await db.select({
  field1: users.id,
  field2: users.name,
}).from(users);

const { field1, field2 } = result[0];
```
```sql
select "id", "name" from "users";
```
</Section>

Like in SQL, you can use arbitrary expressions as selection fields, not just table columns:

<Section>
```typescript
const result = await db.select({
  id: users.id,
  lowerName: sql<string>`lower(${users.name})`,
}).from(users);
```
```sql
select "id", lower("name") from "users";
```
</Section>

<Callout type="warning">
By specifying `sql<string>`, you are telling Drizzle that the **expected** type of the field is `string`.<br />
If you specify it incorrectly (e.g. use `sql<number>` for a field that will be returned as a string), the runtime value won't match the expected type.
Drizzle cannot perform any type casts based on the provided type generic, because that information is not available at runtime.

If you need to apply runtime transformations to the returned value, you can use the [`.mapWith()`](/docs/sql#sqlmapwith) method.
</Callout>

### Conditional select

You can have a dynamic selection object based on some condition:

```typescript
async function selectUsers(withName: boolean) {
  return db
    .select({
      id: users.id,
      ...(withName ? { name: users.name } : {}),
    })
    .from(users);
}

const result = await selectUsers(true);
```

### Distinct select

You can use `.selectDistinct()` instead of `.select()` to retrieve only unique rows from a dataset:
<Section>
```ts
await db.selectDistinct().from(users).orderBy(users.id, users.name);

await db.selectDistinct({ id: users.id }).from(users).orderBy(users.id);
```
```sql
select distinct "id", "name", "age" from "users" order by "users"."id", "users"."name";

select distinct "id" from "users" order by "users"."id";
```
</Section>

In PostgreSQL, you can also use the `distinct on` clause to specify how the unique rows are determined:

<Section>
```ts
await db.selectDistinctOn([users.id]).from(users).orderBy(users.id);
await db.selectDistinctOn([users.name], { name: users.name }).from(users).orderBy(users.name);
```
```sql
select distinct on ("users"."id") "id", "name", "age" from "users" order by "users"."id";
select distinct on ("users"."name") "name" from "users" order by "users"."name";
```
</Section>

### Advanced select
Powered by TypeScript, Drizzle APIs let you build your select queries in a variety of flexible ways.

Sneak peek of advanced partial select, for more detailed advanced usage examples - see our [dedicated guide](/docs/guides/include-or-exclude-columns).

<CodeTabs items={["example 1", "example 2", "example 3", "example 4"]}>
```ts
import { getColumns, sql } from 'drizzle-orm';

await db.select({
    ...getColumns(posts),
    titleLength: sql<number>`length(${posts.title})`,
  }).from(posts);
```
```ts
import { getColumns } from 'drizzle-orm';

const { content, ...rest } = getColumns(posts); // exclude "content" column
await db.select({ ...rest }).from(posts); // select all other columns
```
```ts
await db.query.posts.findMany({
  columns: {
    title: true,
  },
});
```
```ts
await db.query.posts.findMany({
  columns: {
    content: false,
  },
});
```
</CodeTabs>

## ---

### Filters

You can filter the query results using the [filter operators](/docs/operators) in the `.where()` method:

<Section>
```typescript copy
import { eq, lt, gte, ne } from 'drizzle-orm';

await db.select().from(users).where(eq(users.id, 42));
await db.select().from(users).where(lt(users.id, 42));
await db.select().from(users).where(gte(users.id, 42));
await db.select().from(users).where(ne(users.id, 42));
...
```
```sql
select "id", "name", "age" from "users" where "users"."id" = 42;
select "id", "name", "age" from "users" where "users"."id" < 42;
select "id", "name", "age" from "users" where "users"."id" >= 42;
select "id", "name", "age" from "users" where "users"."id" <> 42;
```
</Section>

All filter operators are implemented using the [`sql`](/docs/sql) function.
You can use it yourself to write arbitrary SQL filters, or build your own operators.
For inspiration, you can check how the operators provided by Drizzle are [implemented](https://github.com/drizzle-team/drizzle-orm/blob/main/drizzle-orm/src/sql/expressions/conditions.ts).
<Section>
```typescript copy
import { sql } from 'drizzle-orm';
import type { PgColumn } from "drizzle-orm/pg-core";

function equals42(col: PgColumn) {
  return sql`${col} = 42`;
}

await db.select().from(users).where(sql`${users.id} < 42`);
await db.select().from(users).where(sql`${users.id} = 42`);
await db.select().from(users).where(equals42(users.id));
await db.select().from(users).where(sql`${users.id} >= 42`);
await db.select().from(users).where(sql`${users.id} <> 42`);
await db.select().from(users).where(sql`lower(${users.name}) = 'aaron'`);
```
```sql
select "id", "name", "age" from "users" where "users"."id" < 42;
select "id", "name", "age" from "users" where "users"."id" = 42;
select "id", "name", "age" from "users" where "users"."id" = 42;
select "id", "name", "age" from "users" where "users"."id" >= 42;
select "id", "name", "age" from "users" where "users"."id" <> 42;
select "id", "name", "age" from "users" where lower("users"."name") = 'aaron';
```
</Section>

<Callout type='info'>
All the values provided to filter operators and to the `sql` function are parameterized automatically.
For example, this query:
```ts
await db.select().from(users).where(eq(users.id, 42));
```
will be translated to:
```sql
select "id", "name", "age" from "users" where "users"."id" = $1; -- params: [42]
```
</Callout>

Inverting condition with a `not` operator:
<Section>
```typescript copy
import { eq, not, sql } from 'drizzle-orm';

await db.select().from(users).where(not(eq(users.id, 42)));
await db.select().from(users).where(sql`not ${users.id} = 42`);
```
```sql
select "id", "name", "age" from "users" where not ("users"."id" = 42);
select "id", "name", "age" from "users" where not "users"."id" = 42;
```
</Section>

<Callout type="info">
You can safely alter schema, rename tables and columns
and it will be automatically reflected in your queries because of template interpolation,
as opposed to hardcoding column or table names when writing raw SQL.
</Callout>

### Combining filters
You can logically combine filter operators with `and()` and `or()` operators:
<Section>
```typescript copy
import { eq, and, sql } from 'drizzle-orm';

await db.select().from(users).where(
  and(
    eq(users.id, 42),
    eq(users.name, 'Dan')
  )
);
await db.select().from(users).where(sql`${users.id} = 42 and ${users.name} = 'Dan'`);
```
```sql
select "id", "name", "age" from "users" where (("users"."id" = 42) and ("users"."name" = 'Dan'));
select "id", "name", "age" from "users" where "users"."id" = 42 and "users"."name" = 'Dan';
```
</Section>

<Section>
```typescript copy
import { eq, or, sql } from 'drizzle-orm';

await db.select().from(users).where(
  or(
    eq(users.id, 42), 
    eq(users.name, 'Dan')
  )
);
await db.select().from(users).where(sql`${users.id} = 42 or ${users.name} = 'Dan'`);
```
```sql
select "id", "name", "age" from "users" where (("users"."id" = 42) or ("users"."name" = 'Dan'));
select "id", "name", "age" from "users" where "users"."id" = 42 or "users"."name" = 'Dan';
```
</Section>

### Advanced filters
In combination with TypeScript, Drizzle APIs provide you powerful and flexible ways to combine filters in queries.

Sneak peek of conditional filtering, for more detailed advanced usage examples - see our [dedicated guide](/docs/guides/conditional-filters-in-query).
<CodeTabs items={["example 1", "example 2"]}>
```ts
const searchPosts = async (term?: string) => {
  await db
    .select()
    .from(posts)
    .where(term ? ilike(posts.title, term) : undefined);
};
await searchPosts();
await searchPosts('AI');
```
```ts
const searchPosts = async (filters: SQL[]) => {
  await db
    .select()
    .from(posts)
    .where(and(...filters));
};
const filters: SQL[] = [];
filters.push(ilike(posts.title, 'AI'));
filters.push(inArray(posts.category, ['Tech', 'Art', 'Science']));
filters.push(gt(posts.views, 200));
await searchPosts(filters);
```
</CodeTabs>

## ---

### Limit & offset
Use `.limit()` and `.offset()` to add limit and offset clauses to the query - for example, to implement pagination:

```ts
await db.select().from(users).limit(10);
await db.select().from(users).limit(10).offset(10);
```

```sql
select "id", "name", "age" from "users" limit 10;
select "id", "name", "age" from "users" limit 10 offset 10;
```

### Order By
Use `.orderBy()` to add `order by` clause to the query, sorting the results by the specified fields:
<Section>
```typescript
import { asc, desc } from 'drizzle-orm';

await db.select().from(users).orderBy(users.name);
await db.select().from(users).orderBy(desc(users.name));

// order by multiple fields
await db.select().from(users).orderBy(users.name, users.name2);
await db.select().from(users).orderBy(asc(users.name), desc(users.name2));
```
```sql
select "id", "name", "name2", "age" from "users" order by "users"."name";
select "id", "name", "name2", "age" from "users" order by "users"."name" desc;

select "id", "name", "name2", "age" from "users" order by "users"."name", "users"."name";
select "id", "name", "name2", "age" from "users" order by "users"."name" asc, "users"."name2" desc;
```
</Section>

### Advanced pagination
Powered by TypeScript, Drizzle APIs let you implement all possible SQL pagination and sorting approaches.

Sneak peek of advanced pagination, for more detailed advanced
usage examples - see our dedicated [limit offset pagination](/docs/guides/limit-offset-pagination)
and [cursor pagination](/docs/guides/cursor-based-pagination) guides.

<CodeTabs items={["example 1", "example 2", "example 3", "example 4"]}>
```ts
await db
  .select()
  .from(users)
  .orderBy(asc(users.id)) // order by is mandatory
  .limit(4) // the number of rows to return
  .offset(4); // the number of rows to skip
```
```ts
const getUsers = async (page = 1, pageSize = 3) => {
  return await db.query.users.findMany({
    orderBy: (users, { asc }) => asc(users.id),
    limit: pageSize,
    offset: (page - 1) * pageSize,
  });
};
await getUsers();
```
```ts
const getUsers = async (page = 1, pageSize = 10) => {
   const sq = db
    .select({ id: users.id })
    .from(users)
    .orderBy(users.id)
    .limit(pageSize)
    .offset((page - 1) * pageSize)
    .as('subquery');
   return await db.select().from(users).innerJoin(sq, eq(users.id, sq.id)).orderBy(users.id);
};
```
```ts
const nextUserPage = async (cursor?: number, pageSize = 3) => {
  return await db
    .select()
    .from(users)
    .where(cursor ? gt(users.id, cursor) : undefined) // if cursor is provided, get rows after it
    .limit(pageSize) // the number of rows to return
    .orderBy(asc(users.id)); // ordering
};
// pass the cursor of the last row of the previous page (id)
await nextUserPage(3);
```
</CodeTabs>

## ---

### WITH clause

<Callout>
  Check how to use WITH statement with [insert](/docs/insert#with-insert-clause), [update](/docs/update#with-update-clause), [delete](/docs/delete#with-delete-clause)
</Callout>

Using the `with` clause can help you simplify complex queries by splitting them into smaller subqueries called common table expressions (CTEs):
<Section>
```typescript copy
const sq = db.$with('sq').as(db.select().from(users).where(eq(users.id, 42)));

const result = await db.with(sq).select().from(sq);
```
```sql
with "sq" as (select "id", "name", "age" from "users" where "users"."id" = 42)
select "id", "name", "age" from "sq";
```
</Section>

You can also provide `insert`, `update` and `delete` statements inside `with`

<Section>
```typescript copy
const sq = db.$with('sq').as(
    db.insert(users).values({ name: 'John' }).returning(),
);

const result = await db.with(sq).select().from(sq);
```
```sql
with "sq" as (insert into "users" ("id", "name", "age") values (default, 'John', default) returning "id", "name", "age")
select "id", "name", "age" from "sq";
```
</Section>

<Section>
```typescript copy
const sq = db.$with('sq').as(
    db.update(users).set({ age: 25 }).where(eq(users.name, 'John')).returning(),
);
const result = await db.with(sq).select().from(sq);
```
```sql
with "sq" as (update "users" set "age" = 25 where "users"."name" = 'John' returning "id", "name", "age") 
select "id", "name", "age" from "sq";
```
</Section>

<Section>
```typescript copy
const sq = db.$with('sq').as(
  db.delete(users).where(eq(users.name, 'John')).returning(),
);

const result = await db.with(sq).select().from(sq);
```
```sql
with "sq" as (delete from "users" where "users"."name" = $1 returning "id", "name", "age") 
select "id", "name", "age" from "sq";
```
</Section>

To select arbitrary SQL values as fields in a CTE and reference them in other CTEs or in the main query,
you need to add aliases to them:
```typescript copy

const sq = db.$with('sq').as(db.select({ 
  name: sql<string>`upper(${users.name})`.as('name'),
})
.from(users));

const result = await db.with(sq).select({ name: sq.name }).from(sq);
```
If you don't provide an alias, the field type will become `DrizzleTypeError` and you won't be able to reference it in other queries.
If you ignore the type error and still try to use the field,
you will get a runtime error, since there's no way to reference that field without an alias.

### Select from subquery
Just like in SQL, you can embed queries into other queries by using the subquery API:
<Section>
```typescript copy
const sq = db.select().from(users).where(eq(users.id, 42)).as('sq');
const result = await db.select().from(sq);
```
```sql
select "id", "name", "age" from (select "id", "name", "age" from "users" where "users"."id" = 42) "sq";
```
</Section>

Subqueries can be used in any place where a table can be used, for example in joins:
<Section>
```typescript copy
const sq = db.select().from(users).where(eq(users.id, 42)).as('sq');
const result = await db.select().from(users).leftJoin(sq, eq(users.id, sq.id));
```
```sql
select "users"."id", "users"."name", "users"."age", "sq"."id", "sq"."name", "sq"."age" from "users"
  left join (select "id", "name", "age" from "users" where "users"."id" = 42) "sq"
    on "users"."id" = "sq"."id";
```
</Section>

## ---

### Aggregations
With Drizzle, you can do aggregations using functions like `sum`, `count`, `avg`, etc. by
grouping and filtering with `.groupBy()` and `.having()` respectfully, same as you would do in raw SQL:

<Section>
```typescript
import { gt, sql } from "drizzle-orm";

await db.select({
  age: users.age,
  count: sql<number>`cast(count(${users.id}) as int)`,
})
  .from(users)
  .groupBy(users.age);

await db.select({
  age: users.age,
  count: sql<number>`cast(count(${users.id}) as int)`,
})
  .from(users)
  .groupBy(users.age)
  .having(({ count }) => gt(count, 1));
```
```sql
select "age", cast(count("id") as int)
  from "users"
  group by "users"."age";

select "age", cast(count("id") as int)
  from "users"
  group by "users"."age"
  having cast(count("users"."id") as int) > 1;
```
</Section>

<Callout type="info">
`cast(... as int)` is necessary because `count()` returns `bigint`/`string` in PostgreSQL.
Alternatively, you can use [`.mapWith(Number)`](/docs/sql#sqlmapwith) to cast the value to a number at runtime.

If you need count aggregation - we recommend using our [$count](/docs/select#count) API
</Callout>

### Aggregations helpers

Drizzle has a set of wrapped `sql` functions, so you don't need to write
`sql` templates for common cases in your app

<Callout type="info">
 Remember, aggregation functions are often used with the GROUP BY clause of the SELECT statement. 
 So if you are selecting using aggregating functions and other columns in one query, 
 be sure to use the `.groupBy` clause
</Callout>

**count**

Returns the number of values in `expression`.
<Section>
```ts
import { count } from 'drizzle-orm'

await db.select({ value: count() }).from(users);
await db.select({ value: count(users.id) }).from(users);
```
```sql
select count(*) from "users";
select count("id") from "users";
```
```ts
// It's equivalent to writing
await db.select({ 
  value: sql`count(*)`.mapWith(Number) 
}).from(users);

await db.select({ 
  value: sql`count(${users.id})`.mapWith(Number) 
}).from(users);
```
</Section>

**countDistinct**

Returns the number of non-duplicate values in `expression`.
<Section>
```ts
import { countDistinct } from 'drizzle-orm'

await db.select({ value: countDistinct(users.id) }).from(users);
```
```sql
select count(distinct "id") from "users";
```
```ts
// It's equivalent to writing
await db.select({ 
  value: sql`count(distinct ${users.id})`.mapWith(Number) 
}).from(users);
```
</Section>

**avg**

Returns the average (arithmetic mean) of all non-null values in `expression`.
<Section>
```ts
import { avg } from 'drizzle-orm'

await db.select({ value: avg(users.id) }).from(users);
```
```sql
select avg("id") from "users";
```
```ts
// It's equivalent to writing
await db.select({ 
  value: sql`avg(${users.id})`.mapWith(String) 
}).from(users);
```
</Section>

**avgDistinct**

Returns the average (arithmetic mean) of all non-null values in `expression`.
<Section>
```ts
import { avgDistinct } from 'drizzle-orm'

await db.select({ value: avgDistinct(users.id) }).from(users);
```
```sql
select avg(distinct "id") from "users";
```
```ts
// It's equivalent to writing
await db.select({ 
  value: sql`avg(distinct ${users.id})`.mapWith(String) 
}).from(users);
```
</Section>

**sum**

Returns the sum of all non-null values in `expression`.
<Section>
```ts
import { sum } from 'drizzle-orm'

await db.select({ value: sum(users.id) }).from(users);
```
```sql
select sum("id") from "users";
```
```ts
// It's equivalent to writing
await db.select({ 
  value: sql`sum(${users.id})`.mapWith(String) 
}).from(users);
```
</Section>

**sumDistinct**

Returns the sum of all non-null and non-duplicate values in `expression`.
<Section>
```ts
import { sumDistinct } from 'drizzle-orm'

await db.select({ value: sumDistinct(users.id) }).from(users);
```
```sql
select sum(distinct "id") from "users";
```
```ts
// It's equivalent to writing
await db.select({ 
  value: sql`sum(distinct ${users.id})`.mapWith(String) 
}).from(users);
```
</Section>

**max**

Returns the maximum value in `expression`.
<Section>
```ts
import { max } from 'drizzle-orm'

await db.select({ value: max(users.id) }).from(users);
```
```sql
select max("id") from "users";
```
```ts
// It's equivalent to writing
await db.select({ 
  value: sql`max(${expression})`.mapWith(users.id) 
}).from(users);
```
</Section>

**min**

Returns the minimum value in `expression`.
<Section>
```ts
import { min } from 'drizzle-orm'

await db.select({ value: min(users.id) }).from(users);
```
```sql
select min("id") from "users";
```
```ts
// It's equivalent to writing
await db.select({ 
  value: sql`min(${users.id})`.mapWith(users.id) 
}).from(users);
```
</Section>

A more advanced example:

```typescript copy
const orders = pgTable("order", {
  id: integer("id").primaryKey(),
  orderDate: timestamp("order_date", { withTimezone: true }).notNull(),
  requiredDate: timestamp("required_date", { withTimezone: true }).notNull(),
  shippedDate: timestamp("shipped_date", { withTimezone: true }),
  shipVia: integer("ship_via").notNull(),
  freight: numeric("freight").notNull(),
  shipName: text("ship_name").notNull(),
  shipCity: text("ship_city").notNull(),
  shipRegion: text("ship_region"),
  shipPostalCode: text("ship_postal_code"),
  shipCountry: text("ship_country").notNull(),
  customerId: text("customer_id").notNull(),
  employeeId: integer("employee_id").notNull(),
});

const details = pgTable("order_detail", {
  unitPrice: numeric("unit_price").notNull(),
  quantity: integer("quantity").notNull(),
  discount: numeric("discount").notNull(),
  orderId: integer("order_id").notNull(),
  productId: integer("product_id").notNull(),
});


await db
  .select({
    id: orders.id,
    shippedDate: orders.shippedDate,
    shipName: orders.shipName,
    shipCity: orders.shipCity,
    shipCountry: orders.shipCountry,
    productsCount: sql<number>`cast(count(${details.productId}) as int)`,
    quantitySum: sql<number>`sum(${details.quantity})`,
    totalPrice: sql<number>`sum(${details.quantity} * ${details.unitPrice})`,
  })
  .from(orders)
  .leftJoin(details, eq(orders.id, details.orderId))
  .groupBy(orders.id)
  .orderBy(asc(orders.id))
```

### $count

<$count/>


Source: https://orm.drizzle.team/docs/pg/sequences

import Callout from '@mdx/Callout.astro';

# Sequences

Sequences in PostgreSQL are special single-row tables created to generate unique identifiers, often used for auto-incrementing primary key values. They provide a thread-safe way to generate unique sequential values across multiple sessions.

```ts
import { pgSchema, pgSequence } from "drizzle-orm/pg-core";

// No params specified
export const customSequence = pgSequence("name");

// Sequence with params
export const customSequence = pgSequence("name", {
      startWith: 100,
      maxValue: 10000,
      minValue: 100,
      cycle: true,
      cache: 10,
      increment: 2
});

// Sequence in custom schema
export const customSchema = pgSchema('custom_schema');
export const customSequence = customSchema.sequence("name");
```


Source: https://orm.drizzle.team/docs/pg/set-operations

import CodeTabs from '@mdx/CodeTabs.astro';
import CodeTab from '@mdx/CodeTab.astro';
import Callout from '@mdx/Callout.astro';
import Section from "@mdx/Section.astro";

# Set Operations

SQL set operations combine the results of multiple query blocks into a single result. 
The SQL standard defines the following three set operations: `UNION`, `INTERSECT`, `EXCEPT`, `UNION ALL`, `INTERSECT ALL`, `EXCEPT ALL`.

### Union
Combine all results from two query blocks into a single result, omitting any duplicates.

Get all names from customers and users tables without duplicates.

<CodeTabs items={["import-pattern", "builder-pattern", "schema.ts"]}>
	<CodeTab>
	```typescript copy
    import { union } from 'drizzle-orm/pg-core'
    import { users, customers } from './schema'

    const allNamesForUserQuery = db.select({ name: users.name }).from(users);

    const result = await union(
		allNamesForUserQuery,
		db.select({ name: customers.name }).from(customers)
	).limit(10);
    ```
    ```sql
    (select "name" from "sellers")
    union
    (select "name" from "customers")
    limit $1 -- params: [10]
    ```
    </CodeTab>
    <CodeTab>
    ```ts copy
    import { users, customers } from './schema'

    const result = await db
      .select({ name: users.name })
      .from(users)
      .union(db.select({ name: customers.name }).from(customers))
      .limit(10);
    ```
    ```sql
    (select "name" from "sellers")
    union
    (select "name" from "customers")
    limit $1 -- params: [10]
    ```
	</CodeTab>
    <CodeTab>
	```typescript copy
    import { integer, pgTable, text, varchar } from "drizzle-orm/pg-core";

    export const users = pgTable('sellers', {
        id: integer().primaryKey(),
        name: varchar({ length: 256 }).notNull(),
        address: text(),
    });
    
    export const customers = pgTable('customers', {
        id: integer().primaryKey(),
        name: varchar({ length: 256 }).notNull(),
        city: text(),
        email: varchar({ length: 256 }).notNull()
    });
    ```
    </CodeTab>
  </CodeTabs>

### Union All
Combine all results from two query blocks into a single result, with duplicates.

Let's consider a scenario where you have two tables, one representing online sales and the other 
representing in-store sales. In this case, you want to combine the data from both tables into a
single result set. Since there might be duplicate transactions, 
you want to keep all the records and not eliminate duplicates.

<CodeTabs items={["import-pattern", "builder-pattern", "schema.ts"]}>
	<CodeTab>
	```typescript copy
    import { unionAll } from 'drizzle-orm/pg-core'
    import { onlineSales, inStoreSales } from './schema'

    const onlineTransactions = db.select({ transaction: onlineSales.transactionId }).from(onlineSales);
    const inStoreTransactions = db.select({ transaction: inStoreSales.transactionId }).from(inStoreSales);

    const result = await unionAll(onlineTransactions, inStoreTransactions);
    ```
    ```sql
    (select "transaction_id" from "online_sales")
    union all
    (select "transaction_id" from "in_store_sales")
    ```
    </CodeTab>
    <CodeTab>
    ```ts copy
    import { onlineSales, inStoreSales } from './schema'

    const result = await db
      .select({ transaction: onlineSales.transactionId })
      .from(onlineSales)
      .unionAll(
        db.select({ transaction: inStoreSales.transactionId }).from(inStoreSales)
      );
    ```
    ```sql
    (select "transaction_id" from "online_sales")
    union all
    (select "transaction_id" from "in_store_sales")
    ```
	</CodeTab>
    <CodeTab>
	```typescript copy
    import { integer, pgTable, text, timestamp, varchar } from "drizzle-orm/pg-core";

    export const onlineSales = pgTable('online_sales', {
        transactionId: integer('transaction_id').primaryKey(),
        productId: integer('product_id').unique(),
        quantitySold: integer('quantity_sold'),
        saleDate: timestamp('sale_date', { mode: 'date' }),
    });
    
    export const inStoreSales = pgTable('in_store_sales', {
        transactionId: integer('transaction_id').primaryKey(),
        productId: integer('product_id').unique(),
        quantitySold: integer('quantity_sold'),
        saleDate: timestamp('sale_date', { mode: 'date' }),
    });
    ```
    </CodeTab>
  </CodeTabs>

### Intersect
Combine only those rows which the results of two query blocks have in common, omitting any duplicates.

Suppose you have two tables that store information about students' course enrollments. 
You want to find the courses that are common between two different departments,
but you want distinct course names, and you're not interested in counting multiple 
enrollments of the same course by the same student.

In this scenario, you want to find courses that are common between the two departments but don't want 
to count the same course multiple times even if multiple students from the same department are enrolled in it.

<CodeTabs items={["import-pattern", "builder-pattern", "schema.ts"]}>
	<CodeTab>
	```typescript copy
    import { intersect } from 'drizzle-orm/pg-core'
    import { depA, depB } from './schema'

    const departmentACourses = db.select({ courseName: depA.courseName }).from(depA);
    const departmentBCourses = db.select({ courseName: depB.courseName }).from(depB);

    const result = await intersect(departmentACourses, departmentBCourses);
    ```
    ```sql
    (select "course_name" from "department_a_courses")
    intersect
    (select "course_name" from "department_b_courses")
    ```
	</CodeTab>
    <CodeTab>
    ```typescript copy
    import { depA, depB } from './schema'

    const result = await db
      .select({ courseName: depA.courseName })
      .from(depA)
      .intersect(db.select({ courseName: depB.courseName }).from(depB));
    ```
    ```sql
    (select "course_name" from "department_a_courses")
    intersect
    (select "course_name" from "department_b_courses")
    ```
    </CodeTab>
    <CodeTab>
	```typescript copy
    import { integer, pgTable, varchar } from "drizzle-orm/pg-core";

    export const depA = pgTable('department_a_courses', {
        studentId: integer('student_id'),
        courseName: varchar('course_name').notNull(),
    });
    
    export const depB = pgTable('department_b_courses', {
        studentId: integer('student_id'),
        courseName: varchar('course_name').notNull(),
    });
    ```
    </CodeTab>
  </CodeTabs>

### Intersect All
Combine only those rows which the results of two query blocks have in common, with duplicates.

Let's consider a scenario where you have two tables containing data about customer orders, and you want 
to identify products that are ordered by both regular customers and VIP customers. In this case, 
you want to keep track of the quantity of each product, even if it's ordered multiple times by 
different customers.

In this scenario, you want to find products that are ordered by both regular customers and VIP customers, 
but you want to retain the quantity information, even if the same product is ordered multiple 
times by different customers.

<CodeTabs items={["import-pattern", "builder-pattern", "schema.ts"]}>
	<Section>
	```typescript copy
    import { intersectAll } from 'drizzle-orm/pg-core'
    import { regularCustomerOrders, vipCustomerOrders } from './schema'

    const regularOrders = db.select({ 
        productId: regularCustomerOrders.productId,
        quantityOrdered: regularCustomerOrders.quantityOrdered }
    ).from(regularCustomerOrders);

    const vipOrders = db.select({ 
        productId: vipCustomerOrders.productId,
        quantityOrdered: vipCustomerOrders.quantityOrdered }
    ).from(vipCustomerOrders);

    const result = await intersectAll(regularOrders, vipOrders);
    ```
    ```sql
    (select "product_id", "quantity_ordered" from "regular_customer_orders")
    intersect all
    (select "product_id", "quantity_ordered" from "vip_customer_orders")
    ```
	</Section>
	<Section>
    ```ts copy
    import { regularCustomerOrders, vipCustomerOrders } from './schema'

    const result = await db
        .select({
          productId: regularCustomerOrders.productId,
          quantityOrdered: regularCustomerOrders.quantityOrdered,
        })
        .from(regularCustomerOrders)
        .intersectAll(
          db
            .select({
              productId: vipCustomerOrders.productId,
              quantityOrdered: vipCustomerOrders.quantityOrdered,
            })
            .from(vipCustomerOrders)
        );
    ```
    ```sql
    (select "product_id", "quantity_ordered" from "regular_customer_orders")
    intersect all
    (select "product_id", "quantity_ordered" from "vip_customer_orders")
    ```
    </Section>
	<Section>
	```typescript copy
    import { integer, pgTable } from "drizzle-orm/pg-core";

    export const regularCustomerOrders = pgTable('regular_customer_orders', {
        customerId: integer('customer_id').primaryKey(),
        productId: integer('product_id').notNull(),
        quantityOrdered: integer('quantity_ordered').notNull(),
    });
    
    export const vipCustomerOrders = pgTable('vip_customer_orders', {
        customerId: integer('customer_id').primaryKey(),
        productId: integer('product_id').notNull(),
        quantityOrdered: integer('quantity_ordered').notNull(),
    });
    ```
    </Section>
  </CodeTabs>

### Except
For two query blocks A and B, return all results from A which are not also present in B, omitting any duplicates.

Suppose you have two tables that store information about employees' project assignments. 
You want to find the projects that are unique to one department 
and not shared with another department, excluding duplicates.

In this scenario, you want to identify the projects that are exclusive to one department and
not shared with the other department. You don't want to count the same project 
multiple times, even if multiple employees from the same department are assigned to it.

<CodeTabs items={["import-pattern", "builder-pattern", "schema.ts"]}>
	<CodeTab>
	```typescript copy
    import { except } from 'drizzle-orm/pg-core'
    import { depA, depB } from './schema'

    const departmentACourses = db.select({ courseName: depA.projectsName }).from(depA);
    const departmentBCourses = db.select({ courseName: depB.projectsName }).from(depB);

    const result = await except(departmentACourses, departmentBCourses);
    ```
    ```sql
    (select "projects_name" from "department_a_projects")
    except
    (select "projects_name" from "department_b_projects")
    ```
	</CodeTab>
    <CodeTab>
    ```ts copy
    import { depA, depB } from './schema'

    const result = await db
        .select({ courseName: depA.projectsName })
        .from(depA)
        .except(db.select({ courseName: depB.projectsName }).from(depB));
    ```
    ```sql
    (select "projects_name" from "department_a_projects")
    except
    (select "projects_name" from "department_b_projects")
    ```
    </CodeTab>
    <CodeTab>
	```typescript copy
    import { integer, pgTable, varchar } from "drizzle-orm/pg-core";

    export const depA = pgTable('department_a_projects', {
        employeeId: integer('employee_id'),
        projectsName: varchar('projects_name').notNull(),
    });
    
    export const depB = pgTable('department_b_projects', {
        employeeId: integer('employee_id'),
        projectsName: varchar('projects_name').notNull(),
    });
    ```
    </CodeTab>
  </CodeTabs>

### Except All
For two query blocks A and B, return all results from A which are not also present in B, with duplicates.

Let's consider a scenario where you have two tables containing data about customer orders, and you want to 
identify products that are exclusively ordered by regular customers (without VIP customers). 
In this case, you want to keep track of the quantity of each product, even if it's ordered multiple times by different regular customers.

In this scenario, you want to find products that are exclusively ordered by regular customers and not 
ordered by VIP customers. You want to retain the quantity information, even if the same product is ordered multiple times by different regular customers.

<CodeTabs items={["import-pattern", "builder-pattern", "schema.ts"]}>
	<CodeTab>
	```typescript copy
    import { exceptAll } from 'drizzle-orm/pg-core'
    import { regularCustomerOrders, vipCustomerOrders } from './schema'

    const regularOrders = db.select({ 
        productId: regularCustomerOrders.productId,
        quantityOrdered: regularCustomerOrders.quantityOrdered }
    ).from(regularCustomerOrders);

    const vipOrders = db.select({ 
        productId: vipCustomerOrders.productId,
        quantityOrdered: vipCustomerOrders.quantityOrdered }
    ).from(vipCustomerOrders);

    const result = await exceptAll(regularOrders, vipOrders);
    ```
    ```sql
    (select "product_id", "quantity_ordered" from "regular_customer_orders")
    except all
    (select "product_id", "quantity_ordered" from "vip_customer_orders")
    ```
	</CodeTab>
    <CodeTab>
    ```ts copy
    import { regularCustomerOrders, vipCustomerOrders } from './schema'
 
    const result = await db
        .select({
          productId: regularCustomerOrders.productId,
          quantityOrdered: regularCustomerOrders.quantityOrdered,
        })
        .from(regularCustomerOrders)
        .exceptAll(
          db
            .select({
              productId: vipCustomerOrders.productId,
              quantityOrdered: vipCustomerOrders.quantityOrdered,
            })
            .from(vipCustomerOrders)
        );
    ```
    ```sql
    (select "product_id", "quantity_ordered" from "regular_customer_orders")
    except all
    (select "product_id", "quantity_ordered" from "vip_customer_orders")
    ```
    </CodeTab>
	<CodeTab>
	```typescript copy
    import { integer, pgTable } from "drizzle-orm/pg-core";

    export const regularCustomerOrders = pgTable('regular_customer_orders', {
        customerId: integer('customer_id').primaryKey(),
        productId: integer('product_id').notNull(),
        quantityOrdered: integer('quantity_ordered').notNull(),
    });
    
    export const vipCustomerOrders = pgTable('vip_customer_orders', {
        customerId: integer('customer_id').primaryKey(),
        productId: integer('product_id').notNull(),
        quantityOrdered: integer('quantity_ordered').notNull(),
    });
    ```
    </CodeTab>
  </CodeTabs>


Source: https://orm.drizzle.team/docs/pg/sql-comments

import Section from '@mdx/Section.astro';
import Callout from '@mdx/Callout.astro';

# SQL Comments

You can add custom tags to any query using the `.comment()` method. These tags are appended as [sqlcommenter](https://google.github.io/sqlcommenter)-formatted comments at the end of each query, 
helping you attach metadata for query tracking, debugging and database traffic control.

The `.comment()` method is available on `select`, `insert`, `update` and `delete` queries.

### String comments
You can pass a raw string as a comment:

<Section>
```ts
db.select().from(users).comment("my_first_tag");
```
```sql
select "id", "name" from "users" /*my_first_tag*/
```
</Section>

<Section>
```ts
db.select().from(users).comment("key='val'");
```
```sql
select "id", "name" from "users" /*key='val'*/
```
</Section>

### Object comments
You can pass an object with key-value pairs for structured tags:

<Section>
```ts
db.select().from(users).comment({ priority: 'high', category: 'analytics' });
```
```sql
select "id", "name" from "users" /*priority='high',category='analytics'*/
```
</Section>

<Section>
```ts
db.select().from(users).comment({ trace: true, route: '/api/users', version: 2 });
```
```sql
select "id", "name" from "users" /*route='%2Fapi%2Fusers',trace='true',version='2'*/
```
</Section>

### Usage with insert, update, delete

<Section>
```ts
db.insert(users).values({ name: 'Dan' }).comment({ operation: 'seed' });
```
```sql
insert into "users" ("name") values ('Dan') /*operation='seed'*/
```
</Section>

<Section>
```ts
db.update(users).set({ name: 'Dan' }).where(eq(users.id, 1)).comment({ operation: 'update' });
```
```sql
update "users" set "name" = 'Dan' where "users"."id" = 1 /*operation='update'*/
```
</Section>

<Section>
```ts
db.delete(users).where(eq(users.id, 1)).comment({ operation: 'cleanup' });
```
```sql
delete from "users" where "users"."id" = 1 /*operation='cleanup'*/
```
</Section>

### Limitations
You can't use `.comment()` after the statement has been prepared. Prepared statements compile the SQL query once and reuse it across executions, 
so the query string is fixed at preparation time and can't be modified afterwards — including appending comments:

```ts
// can't be used
const p = db.select().from().prepare();
// ❌
p.comment({ key: 'val' }).execute();
```

Instead, add the comment before preparing the statement:

```ts
// ✅
db.select().from(users).comment({ key: 'val' }).prepare();
```

Source: https://orm.drizzle.team/docs/pg/sql-schema-declaration

import Callout from '@mdx/Callout.astro';
import SimpleLinkCards from '@mdx/SimpleLinkCards.astro';
import CodeTabs from "@mdx/CodeTabs.astro";
import Section from '@mdx/Section.astro';
import Flex from "@mdx/Flex.astro"
import LinksList from "@mdx/LinksList.astro"

# Drizzle schema

Drizzle lets you define a schema in TypeScript with various models and properties supported by the underlying database. 
When you define your schema, it serves as the source of truth for future modifications in queries (using Drizzle-ORM)
and migrations (using Drizzle-Kit).

<Callout> 
If you are using Drizzle-Kit for the migration process, make sure to export all the models defined in your schema files so that Drizzle-Kit can import them and use them in the migration diff process. 
</Callout>

<CodeTabs items={["Using imports", "Using callback", "Using import *"]}>
```ts
import { integer, pgTable, varchar } from "drizzle-orm/pg-core";

export const usersTable = pgTable("users", {
  id: integer().primaryKey().generatedAlwaysAsIdentity(),
  name: varchar().notNull(),
  age: integer().notNull(),
  email: varchar().notNull().unique(),
});
```
```ts
import { pgTable } from "drizzle-orm/pg-core";

export const usersTable = pgTable("users", (t) => ({
  id: t.integer().primaryKey().generatedAlwaysAsIdentity(),
  name: t.varchar().notNull(),
  age: t.integer().notNull(),
  email: t.varchar().notNull().unique(),
}));
```
```ts
import * as p from "drizzle-orm/pg-core";

export const usersTable = p.pgTable("users", {
  id: p.integer().primaryKey().generatedAlwaysAsIdentity(),
  name: p.varchar().notNull(),
  age: p.integer().notNull(),
  email: p.varchar().notNull().unique(),
});
```
</CodeTabs>

## Organize your schema files 
You can declare your SQL schema directly in TypeScript either in a single `schema.ts` file,
or you can spread them around — whichever you prefer, all the freedom!

#### Schema in 1 file
The most common way to declare your schema with Drizzle is to put all your tables into one `schema.ts` file.

> Note: You can name your schema file whatever you like. For example, it could be `models.ts`, or something else.

This approach works well if you don't have too many table models defined, or if you're okay with keeping them all in one file

Example:
```plaintext
📦 <project root>
 └ 📂 src
    └ 📂 db
       └ 📜 schema.ts
```

In the `drizzle.config.ts` file, you need to specify the path to your schema file. With this configuration, Drizzle will 
read from the `schema.ts` file and use this information during the migration generation process. For more information 
about the `drizzle.config.ts` file and migrations with Drizzle, please check: [link](/docs/drizzle-config-file)
```ts
import { defineConfig } from "drizzle-kit";

export default defineConfig({
  dialect: 'postgresql',
  schema: './src/db/schema.ts'
})
```

#### Schema in multiple files

You can place your Drizzle models — such as tables, enums, sequences, etc. — not only in one file but in any file you prefer. 
The only thing you must ensure is that you export all the models from those files so that the Drizzle kit can import 
them and use them in migrations.

One use case would be to separate each table into its own file.
```plaintext
📦 <project root>
 └ 📂 src
    └ 📂 db
       └ 📂 schema
          ├ 📜 users.ts
          ├ 📜 countries.ts
          ├ 📜 cities.ts
          ├ 📜 products.ts
          ├ 📜 clients.ts
          └ 📜 etc.ts
```

In the `drizzle.config.ts` file, you need to specify the path to your schema folder. With this configuration, Drizzle will 
read from the `schema` folder and find all the files recursively and get all the drizzle tables from there. For more information 
about the `drizzle.config.ts` file and migrations with Drizzle, please check: [link](/docs/drizzle-config-file)

```ts
import { defineConfig } from "drizzle-kit";

export default defineConfig({
  dialect: 'postgresql',
  schema: './src/db/schema'
})
```

You can also group them in any way you like, such as creating groups for user-related tables, messaging-related tables, product-related tables, etc. 
```plaintext
📦 <project root>
 └ 📂 src
    └ 📂 db
       └ 📂 schema
          ├ 📜 users.ts
          ├ 📜 messaging.ts
          └ 📜 products.ts
```

## Shape your data schema

Drizzle schema consists of several model types from database you are using. With drizzle you can specify:
- Tables with columns, constraints, etc.
- Schemas
- Enums
- Sequences
- Views
- Materialized Views
- etc.

Let's go one by one and check how the schema should be defined with drizzle

#### **Tables and columns declaration** 

A table in Drizzle should be defined with at least 1 column, the same as it should be done in database. There is one important thing to know,
there is no such thing as a common table object in drizzle. You need to choose a dialect you are using, PostgreSQL, MySQL, SQLite, etc.

![](@/assets/images/table-structure.svg)

```ts copy
import { pgTable, integer } from "drizzle-orm/pg-core"

export const users = pgTable('users', {
  id: integer()
});
```

By default, Drizzle will use the TypeScript key names for columns in database queries. 
Therefore, the schema and query from the example will generate the SQL query shown below

<Callout>
This example uses a db object, whose initialization is not covered in this part of the documentation. To learn how to connect to the database, please refer to the [Connections Docs](/docs/get-started-postgresql)
</Callout>

\
**TypeScript key = database key**
<Section>
```ts
// schema.ts
import { integer, pgTable, varchar } from "drizzle-orm/pg-core";

export const users = pgTable('users', {
  id: integer(),
  first_name: varchar()
})
```
```ts
// query.ts
await db.select().from(users);
```
```sql
SELECT "id", "first_name" from users;
```
</Section>

If you want to use different names in your TypeScript code and in the database, you can use column aliases

<Section>
```ts
// schema.ts
import { integer, pgTable, varchar } from "drizzle-orm/pg-core";

export const users = pgTable('users', {
  id: integer(),
  firstName: varchar('first_name')
})
```
```ts
// query.ts
await db.select().from(users);
```
```sql
SELECT "id", "first_name" from users;
```
</Section>

### Camel and Snake casing

Database model names often use `snake_case` conventions, while in TypeScript, it is common to use `camelCase` for naming models.
This can lead to a lot of alias definitions in the schema. To address this, Drizzle provides a way to automatically
map `camelCase` from TypeScript to `snake_case` in the database via a dedicated builder.

Use the `snakeCase` or `camelCase` builder from `drizzle-orm/pg-core` to declare a table whose column keys are
automatically mapped to the chosen database naming convention

<Section>
```ts {2,4,11,12}
// schema.ts
import { snakeCase, camelCase } from 'drizzle-orm/pg-core';

export const users = snakeCase.table('users', {
  id: serial().primaryKey(),
  fullName: text(),        // → full_name in DB
  createdAt: timestamp(),  // → created_at in DB
});

// Available on all entity types:
snakeCase.table / snakeCase.view / snakeCase.materializedView / snakeCase.schema
camelCase.table / camelCase.view / camelCase.materializedView / camelCase.schema
```
```ts
// db.ts
import { drizzle } from "drizzle-orm/node-postgres";

const db = drizzle({ connection: process.env.DATABASE_URL })
```
```ts
// query.ts
await db.select().from(users);
```
```sql
select "id", "full_name", "created_at" from "users"
```
</Section>

### Advanced

There are a few tricks you can use with Drizzle ORM. As long as Drizzle is entirely in TypeScript files, 
you can essentially do anything you would in a simple TypeScript project with your code.

One common feature is to separate columns into different places and then reuse them. 
For example, consider the `updated_at`, `created_at`, and `deleted_at` columns. Many tables/models may need these 
three fields to track and analyze the creation, deletion, and updates of entities in a system

We can define those columns in a separate file and then import and spread them across all the table objects you have

<Section>
```ts
// columns.helpers.ts
export const timestamps = {
  updated_at: timestamp(),
  created_at: timestamp().defaultNow().notNull(),
  deleted_at: timestamp(),
}
```
```ts
// users.sql.ts
export const users = pgTable('users', {
  id: integer(),
  ...timestamps
})
```
```ts
// posts.sql.ts
export const posts = pgTable('posts', {
  id: integer(),
  ...timestamps
})
```
</Section>

#### **Schemas**

\
In PostgreSQL, there is an entity called a `schema` (which we believe should be called `folders`). This creates a structure in PostgreSQL:

![](@/assets/images/postgresql-db-structure.png)

You can manage your PostgreSQL schemas with `pgSchema` and place any other models inside it.

Define the schema you want to manage using Drizzle
```ts
import { pgSchema } from "drizzle-orm/pg-core"

export const customSchema = pgSchema('custom');
```

Then place the table inside the schema object
```ts {5-7}
import { integer, pgSchema } from "drizzle-orm/pg-core";

export const customSchema = pgSchema('custom');

export const users = customSchema.table('users', {
  id: integer()
})
```

### Example

Once you know the basics, let's define a schema example for a real project to get a better view and understanding

> All examples will use `generateUniqueString`. The implementation for it will be provided after all the schema examples

```ts copy
import type { AnyPgColumn } from "drizzle-orm/pg-core";
import { pgEnum, pgTable as table } from "drizzle-orm/pg-core";
import * as t from "drizzle-orm/pg-core";

export const rolesEnum = pgEnum("roles", ["guest", "user", "admin"]);

export const users = table(
  "users",
  {
    id: t.integer().primaryKey().generatedAlwaysAsIdentity(),
    firstName: t.varchar("first_name", { length: 256 }),
    lastName: t.varchar("last_name", { length: 256 }),
    email: t.varchar().notNull(),
    invitee: t.integer().references((): AnyPgColumn => users.id),
    role: rolesEnum().default("guest"),
  },
  (table) => [
    t.uniqueIndex("email_idx").on(table.email)
  ]
);

export const posts = table(
  "posts",
  {
    id: t.integer().primaryKey().generatedAlwaysAsIdentity(),
    slug: t.varchar().$default(() => generateUniqueString(16)),
    title: t.varchar({ length: 256 }),
    ownerId: t.integer("owner_id").references(() => users.id),
  },
  (table) => [
    t.uniqueIndex("slug_idx").on(table.slug),
    t.index("title_idx").on(table.title),
  ]
);

export const comments = table("comments", {
  id: t.integer().primaryKey().generatedAlwaysAsIdentity(),
  text: t.varchar({ length: 256 }),
  postId: t.integer("post_id").references(() => posts.id),
  ownerId: t.integer("owner_id").references(() => users.id),
});
```

**`generateUniqueString` implementation:**
```ts
function generateUniqueString(length: number = 12): string {
  const characters =
    "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
  let uniqueString = "";

  for (let i = 0; i < length; i++) {
    const randomIndex = Math.floor(Math.random() * characters.length);
    uniqueString += characters[randomIndex];
  }

  return uniqueString;
}
```

#### What's next?
<br/>
<Flex>
  <LinksList 
    title='Manage schema'
    links={[
        ["Column types", "/docs/column-types"], 
        ["Indexes and Constraints", "/docs/indexes-constraints"],
        ["Database Views", "/docs/views"],
        ["Database Schemas", "/docs/schemas"],
        ["Sequences", "/docs/sequences"],
        ["Extensions", "/docs/extensions"],
      ]}
  />
  <LinksList 
    title='Zero to Hero'
    links={[
        ["Database connection", "/docs/connect-overview"], 
        ["Data querying", "/docs/data-querying"], 
        ["Migrations", "/docs/migrations"], 
      ]}
  />
</Flex>


Source: https://orm.drizzle.team/docs/pg/sql

import Callout from '@mdx/Callout.astro';
import Section from '@mdx/Section.astro';

# Magical `sql` operator 🪄

When working with an ORM library, there may be cases where you find it challenging to write a
specific query using the provided ORM syntax. In such situations, you can resort to using
raw queries, which involve constructing a query as a raw string. However, raw queries often
lack the benefits of type safety and query parameterization.

To address this, many libraries have introduced the concept of an `sql` template. This template 
allows you to write more type-safe and parameterized queries, enhancing the overall safety and 
flexibility of your code. Drizzle, being a powerful ORM library, also supports the sql template.

With Drizzle's `sql` template, you can go even further in crafting queries. If you encounter 
difficulties in writing an entire query using the library's query builder, you can selectively
use the `sql` template within specific sections of the Drizzle query. This flexibility enables you 
to employ the sql template in partial SELECT statements, WHERE clauses, ORDER BY clauses, HAVING
clauses, GROUP BY clauses, and even in relational query builders.

By leveraging the capabilities of the sql template in Drizzle, you can maintain the advantages 
of type safety and query parameterization while achieving the desired query structure and complexity.
This empowers you to create more robust and maintainable code within your application.

## sql`` template

One of the most common usages you may encounter in other ORMs as well 
is the ability to use `sql` queries as-is for raw queries.

```typescript copy
import { sql } from 'drizzle-orm' 

const id = 69;
await db.execute(sql`select * from ${usersTable} where ${usersTable.id} = ${id}`)
```

It will generate the current query

```sql
select * from "users" where "users"."id" = $1; --> [69]
```

Any tables and columns provided to the sql parameter are automatically mapped to their corresponding SQL 
syntax with escaped names for tables, and the escaped table names are appended to column names. 

Additionally, any dynamic parameters such as `${id}` will be mapped to the $1 placeholder, 
and the corresponding values will be moved to an array of values that are passed separately to the database. 

This approach effectively prevents any potential SQL Injection vulnerabilities.

## `sql<T>`

<Callout type="info" emoji="ℹ️">
    Please note that `sql<T>` does not perform any runtime mapping. The type you define using `sql<T>` is
    purely a helper for Drizzle. It is important to understand that there is no feasible way to 
    determine the exact type dynamically, as SQL queries can be highly versatile and customizable. 
</Callout>

You can define a custom type in Drizzle to be used in places where fields require a specific type other than `unknown`.

This feature is particularly useful in partial select queries, ensuring consistent typing for selected fields:

```typescript
// without sql<T> type defined
const response: { lowerName: unknown }[] = await db.select({
    lowerName: sql`lower(${usersTable.id})`
}).from(usersTable);

// with sql<T> type defined
const response: { lowerName: string }[] = await db.select({
    lowerName: sql<string>`lower(${usersTable.id})`
}).from(usersTable);
```

## `sql``.mapWith()`

For the cases you need to make a runtime mapping for values passed from database driver to drizzle you can use `.mapWith()`

This function accepts different values, that will map response in runtime.

You can replicate a specific column mapping strategy as long as
the interface inside mapWith is the same interface that is implemented by Column.

```typescript
const usersTable = pgTable('users', {
    id: serial('id').primaryKey(),
    name: text('name').notNull(),
});

//  at runtime this values will be mapped same as `text` column is mapped in drizzle
sql`...`.mapWith(usersTable.name);
```

You can also pass your own implementation for the `DriverValueDecoder` interface:

```ts 
sql``.mapWith({
	mapFromDriverValue: (value: any) => {
		const mappedValue = value;
		// mapping you want to apply
		return mappedValue;
	},
});
    
// or
sql``.mapWith(Number);
```

## `sql``.as<T>()`

In different cases, it can sometimes be challenging to determine how to name a custom field that you want to use.
You may encounter situations where you need to explicitly specify an alias for a 
field that will be selected. This can be particularly useful when dealing with complex queries. 

To address these scenarios, we have introduced a helpful `.as('alias_name')` helper, which allows 
you to define an alias explicitly. By utilizing this feature, you can provide a clear and meaningful 
name for the field, making your queries more intuitive and readable.

<Section>
```typescript
sql`lower(${usersTable.name})`.as('lower_name')
```
```sql
... "users"."name" as lower_name ...
```
</Section>

## `sql.raw()`

There are cases where you may not need to create parameterized values from input or map tables/columns to escaped ones. 
Instead, you might simply want to generate queries as they are. For such situations, we provide the `sql.raw()` function.

The `sql.raw()` function allows you to include raw SQL statements within your queries without any additional processing or escaping.
This can be useful when you have pre-constructed SQL statements or when you need to incorporate complex or dynamic 
SQL code directly into your queries.

<Section>
```typescript
sql.raw(`select * from users where id = ${12}`);
// vs
sql`select * from users where id = ${12}`;
```
```sql
select * from users where id = 12;
--> vs
select * from users where id = $1; --> [12]
```
</Section>

You can also utilize `sql.raw()` within the sql function, enabling you to include any raw string
without escaping it through the main `sql` template function.

By using `sql.raw()` inside the `sql` function, you can incorporate unescaped raw strings 
directly into your queries. This can be particularly useful when you have specific
SQL code or expressions that should remain untouched by the template function's automatic escaping or modification.

<Section>
```typescript
sql`select * from ${usersTable} where id = ${12}`;
// vs
sql`select * from ${usersTable} where id = ${sql.raw(12)}`;
```
```sql
select * from "users" where id = $1; --> [12]
--> vs
select * from "users" where id = 12;
```
</Section>

## sql.fromList()

The `sql` template generates sql chunks, which are arrays of SQL parts that will be concatenated 
into the query and params after applying the SQL to the database or query in Drizzle.

In certain scenarios, you may need to aggregate these chunks into an array using custom business 
logic and then concatenate them into a single SQL statement that can be passed to the database or query.
For such cases, the fromList function can be quite useful.

The fromList function allows you to combine multiple SQL chunks into a single SQL statement. 
You can use it to aggregate and concatenate the individual SQL parts according to your specific 
requirements and then obtain a unified SQL query that can be executed.

<Section>
```typescript
const sqlChunks: SQL[] = [];

sqlChunks.push(sql`select * from users`);

// some logic

sqlChunks.push(sql` where `);

// some logic

for (let i = 0; i < 5; i++) {
	sqlChunks.push(sql`id = ${i}`);

	if (i === 4) continue;
	sqlChunks.push(sql` or `);
}

const finalSql: SQL = sql.fromList(sqlChunks)
```
```sql
select * from users where id = $1 or id = $2 or id = $3 or id = $4 or id = $5; --> [0, 1, 2, 3, 4]
```
</Section>

## sql.join()

Indeed, the `sql.join` function serves a similar purpose to the fromList helper. 
However, it provides additional flexibility when it comes to handling spaces between
SQL chunks or specifying custom separators for concatenating the SQL chunks.

With `sql.join`, you can concatenate SQL chunks together using a specified separator. 
This separator can be any string or character that you want to insert between the chunks. 

This is particularly useful when you have specific requirements for formatting or delimiting 
the SQL chunks. By specifying a custom separator, you can achieve the desired structure and formatting 
in the final SQL query.

<Section>
```typescript
const sqlChunks: SQL[] = [];

sqlChunks.push(sql`select * from users`);

// some logic

sqlChunks.push(sql`where`);

// some logic

for (let i = 0; i < 5; i++) {
	sqlChunks.push(sql`id = ${i}`);

if (i === 4) continue;
    sqlChunks.push(sql`or`);
}

const finalSql: SQL = sql.join(sqlChunks, sql.raw(' '));
```
```sql
select * from users where id = $1 or id = $2 or id = $3 or id = $4 or id = $5; --> [0, 1, 2, 3, 4]
```
</Section>

## sql.append()

If you have already generated SQL using the `sql` template, you can achieve the same behavior as `fromList`
by using the append function to directly add a new chunk to the generated SQL.

By using the append function, you can dynamically add additional SQL chunks to the existing SQL string,
effectively concatenating them together. This allows you to incorporate custom logic or business 
rules for aggregating the chunks into the final SQL query.

<Section>
```typescript 
const finalSql = sql`select * from users`;

// some logic

finalSql.append(sql` where `);

// some logic

for (let i = 0; i < 5; i++) {
	finalSql.append(sql`id = ${i}`);

	if (i === 4) continue;
	finalSql.append(sql` or `);
}
```
```sql
select * from users where id = $1 or id = $2 or id = $3 or id = $4 or id = $5; --> [0, 1, 2, 3, 4]
```
</Section>

## sql.empty()

By using sql.empty(), you can start with a blank SQL object and then dynamically append SQL chunks to it as needed. This allows you to construct the SQL query incrementally, applying custom logic or conditions to determine the contents of each chunk.

Once you have initialized the SQL object using sql.empty(), you can take advantage of the full range
of sql template features such as parameterization, composition, and escaping. 
This empowers you to construct the SQL query in a flexible and controlled manner, 
adapting it to your specific requirements.

```typescript 
const finalSql = sql.empty();

// some logic

finalSql.append(sql`select * from users`);

// some logic

finalSql.append(sql` where `);

// some logic

for (let i = 0; i < 5; i++) {
	finalSql.append(sql`id = ${i}`);

	if (i === 4) continue;
	finalSql.append(sql` or `);
}
```
```sql
select * from users where id = $1 or id = $2 or id = $3 or id = $4 or id = $5; --> [0, 1, 2, 3, 4]
```

## Convert `sql` to string and params

In all the previous examples, you observed the usage of SQL template syntax in TypeScript along with 
the generated SQL output.

If you need to obtain the query string and corresponding parameters generated from the SQL template, 
you must specify the database dialect you intend to generate the query for. Different databases have
varying syntax for parameterization and escaping, so selecting the appropriate dialect is crucial.

Once you have chosen the dialect, you can utilize the corresponding implementation's functionality
to convert the SQL template into the desired query string and parameter format. This ensures 
compatibility with the specific database system you are working with.

<Section>
```typescript copy
import { PgDialect } from 'drizzle-orm/pg-core';

const pgDialect = new PgDialect();
pgDialect.sqlToQuery(sql`select * from ${usersTable} where ${usersTable.id} = ${12}`);
```
```sql
select * from "users" where "users"."id" = $1; --> [ 12 ]
```
</Section>

## `sql` select

You can use the sql functionality in partial select queries as well. Partial select queries allow you to 
retrieve specific fields or columns from a table rather than fetching the entire row.

For more detailed information about partial select queries, you can refer to the Core API
documentation available at **[Core API docs](/docs/select#basic-and-partial-select)**.

**Select different custom fields from table**

Here you can see a usage for **[`sql<T>`](/docs/sql#sqlt)**, **[`sql``.mapWith()`](/docs/sql#sqlmapwith)**, **[`sql``.as<T>()`](/docs/sql#sqlast)**.

<Section>
```typescript copy
import { sql } from 'drizzle-orm'
import { usersTable } from './schema'

await db.select({
    id: usersTable.id,
    lowerName: sql<string>`lower(${usersTable.name})`,
    aliasedName: sql<string>`lower(${usersTable.name})`.as('aliased_column'),
    count: sql<number>`count(*)`.mapWith(Number) 
}).from(usersTable)
```
```sql
select "id", lower("name"), lower("name") as "aliased_column", count(*) from "users";
```
</Section>

## `sql` in where

Indeed, Drizzle provides a set of available expressions that you can use within the sql template. 
However, it is true that databases often have a wider range of expressions available, 
including those provided through extensions or other means.

To ensure flexibility and enable you to utilize any expressions that are not natively
supported by Drizzle, you have the freedom to write the SQL template
directly using the sql function. This allows you to leverage the full power of
SQL and incorporate any expressions or functionalities specific to your target database.

By using the sql template, you are not restricted to only the predefined expressions in Drizzle. 
Instead, you can express complex queries and incorporate any supported expressions that 
the underlying database system provides.

**Filtering by `id` but with sql**
<Section>
```typescript copy
import { sql } from 'drizzle-orm'
import { usersTable } from './schema'

const id = 77

await db.select()
        .from(usersTable)
        .where(sql`${usersTable.id} = ${id}`)
```
```sql
select * from "users" where "users"."id" = $1; --> [ 77 ]
```
</Section>

**Advanced fulltext search where statement**
<Section>
```typescript copy
import { sql } from 'drizzle-orm'
import { usersTable } from './schema'

const searchParam = "Ale"

await db.select()
        .from(usersTable)
        .where(sql`to_tsvector('simple', ${usersTable.name}) @@ to_tsquery('simple', ${searchParam})`)
```
```sql
select * from "users" where to_tsvector('simple', "users"."name") @@ to_tsquery('simple', '$1'); --> [ "Ale" ]
```
</Section>

## `sql` in orderBy

The `sql` template can indeed be used in the ORDER BY clause when you need specific functionality for ordering that is not
available in Drizzle, but you prefer not to resort to raw SQL.

<Section>
```typescript copy
import { sql } from 'drizzle-orm'
import { usersTable } from './schema'

await db.select().from(usersTable).orderBy(sql`${usersTable.id} desc nulls first`)
```
```sql
select * from "users" order by "users"."id" desc nulls first;
```
</Section>

## `sql` in having and groupBy

The `sql` template can indeed be used in the HAVING and GROUP BY clauses when you need specific functionality for ordering that is not
available in Drizzle, but you prefer not to resort to raw SQL.

<Section>
```typescript copy
import { sql } from 'drizzle-orm'
import { usersTable } from './schema'

await db.select({ 
    projectId: usersTable.projectId,
    count: sql<number>`count(${usersTable.id})`.mapWith(Number)
}).from(usersTable)
    .groupBy(sql`${usersTable.projectId}`)
    .having(sql`count(${usersTable.id}) > 300`)
```
```sql
select "project_id", count("id") from "users" group by "users"."project_id" having count("users"."id") > 300
```
</Section>


Source: https://orm.drizzle.team/docs/pg/transactions

# Transactions

SQL transaction is a grouping of one or more SQL statements that interact with a database.
A transaction in its entirety can commit to a database as a single logical unit
or rollback (become undone) as a single logical unit.

Drizzle ORM provides APIs to run SQL statements in transactions:

```ts copy
const db = drizzle(...)

await db.transaction(async (tx) => {
  await tx.update(accounts).set({ balance: sql`${accounts.balance} - 100.00` }).where(eq(users.name, 'Dan'));
  await tx.update(accounts).set({ balance: sql`${accounts.balance} + 100.00` }).where(eq(users.name, 'Andrew'));
});
```

Drizzle ORM supports `savepoints` with nested transactions API:

```ts copy {7-9}
const db = drizzle(...)

await db.transaction(async (tx) => {
  await tx.update(accounts).set({ balance: sql`${accounts.balance} - 100.00` }).where(eq(users.name, 'Dan'));
  await tx.update(accounts).set({ balance: sql`${accounts.balance} + 100.00` }).where(eq(users.name, 'Andrew'));

  await tx.transaction(async (tx2) => {
    await tx2.update(users).set({ name: "Mr. Dan" }).where(eq(users.name, "Dan"));
  });
});
```

You can embed business logic to the transaction and rollback whenever needed:

```ts copy {7}
const db = drizzle(...)

await db.transaction(async (tx) => {
  const [account] = await tx.select({ balance: accounts.balance }).from(accounts).where(eq(users.name, 'Dan'));
  if (account.balance < 100) {
    // This throws an exception that rollbacks the transaction.
    tx.rollback()
  }

  await tx.update(accounts).set({ balance: sql`${accounts.balance} - 100.00` }).where(eq(users.name, 'Dan'));
  await tx.update(accounts).set({ balance: sql`${accounts.balance} + 100.00` }).where(eq(users.name, 'Andrew'));
});
```

You can return values from the transaction:

```ts copy {8}
const db = drizzle(...)

const newBalance: number = await db.transaction(async (tx) => {
  await tx.update(accounts).set({ balance: sql`${accounts.balance} - 100.00` }).where(eq(users.name, 'Dan'));
  await tx.update(accounts).set({ balance: sql`${accounts.balance} + 100.00` }).where(eq(users.name, 'Andrew'));

  const [account] = await tx.select({ balance: accounts.balance }).from(accounts).where(eq(users.name, 'Dan'));
  return account.balance;
});
```

You can use transactions with **[relational queries](/docs/rqb)**:

```ts
const db = drizzle({ schema })

await db.transaction(async (tx) => {
  await tx.query.users.findMany({
    with: {
      accounts: true
    }
  });
});
```

We provide dialect-specific transaction configuration APIs:

```ts copy {6-8}
await db.transaction(
  async (tx) => {
    await tx.update(accounts).set({ balance: sql`${accounts.balance} - 100.00` }).where(eq(users.name, "Dan"));
    await tx.update(accounts).set({ balance: sql`${accounts.balance} + 100.00` }).where(eq(users.name, "Andrew"));
  }, {
    isolationLevel: "read committed",
    accessMode: "read write",
    deferrable: true,
  }
);

interface PgTransactionConfig {
  isolationLevel?:
    | "read uncommitted"
    | "read committed"
    | "repeatable read"
    | "serializable";
  accessMode?: "read only" | "read write";
  deferrable?: boolean;
}
```


Source: https://orm.drizzle.team/docs/pg/typebox-legacy

import Npm from '@mdx/Npm.astro';
import Callout from '@mdx/Callout.astro';

# typebox-legacy

### Install the dependencies
<Npm>
drizzle-orm@rc @sinclair/typebox
</Npm>

### Select schema

Defines the shape of data queried from the database - can be used to validate API responses.

```ts copy
import { pgTable, text, integer } from 'drizzle-orm/pg-core';
import { createSelectSchema } from 'drizzle-orm/typebox-legacy';
import { Value } from '@sinclair/typebox/value';

const users = pgTable('users', {
  id: integer().generatedAlwaysAsIdentity().primaryKey(),
  name: text().notNull(),
  age: integer().notNull()
});

const userSelectSchema = createSelectSchema(users);

const rows = await db.select({ id: users.id, name: users.name }).from(users).limit(1);
const parsed: { id: number; name: string; age: number } = Value.Parse(userSelectSchema, rows[0]); // Error: `age` is not returned in the above query

const rows = await db.select().from(users).limit(1);
const parsed: { id: number; name: string; age: number } = Value.Parse(userSelectSchema, rows[0]); // Will parse successfully
```

Views and enums are also supported.

```ts copy
import { pgEnum, pgView } from 'drizzle-orm/pg-core';
import { gt } from 'drizzle-orm';
import { createSelectSchema } from 'drizzle-orm/typebox-legacy';
import { Value } from '@sinclair/typebox/value';

const roles = pgEnum('roles', ['admin', 'basic']);
const rolesSchema = createSelectSchema(roles);
const parsed: 'admin' | 'basic' = Value.Parse(rolesSchema, ...);

const usersView = pgView('users_view').as((qb) => qb.select().from(users).where(gt(users.age, 18)));
const usersViewSchema = createSelectSchema(usersView);
const parsed: { id: number; name: string; age: number } = Value.Parse(usersViewSchema, ...);
```

### Insert schema

Defines the shape of data to be inserted into the database - can be used to validate API requests.

```ts copy
import { pgTable, text, integer } from 'drizzle-orm/pg-core';
import { createInsertSchema } from 'drizzle-orm/typebox-legacy';
import { Value } from '@sinclair/typebox/value';

const users = pgTable('users', {
  id: integer().generatedAlwaysAsIdentity().primaryKey(),
  name: text().notNull(),
  age: integer().notNull()
});

const userInsertSchema = createInsertSchema(users);

const user = { name: 'John' };
const parsed: { name: string, age: number } = Value.Parse(userInsertSchema, user); // Error: `age` is not defined

const user = { name: 'Jane', age: 30 };
const parsed: { name: string, age: number } = Value.Parse(userInsertSchema, user); // Will parse successfully
await db.insert(users).values(parsed);
```

### Update schema

Defines the shape of data to be updated in the database - can be used to validate API requests.

```ts copy
import { pgTable, text, integer } from 'drizzle-orm/pg-core';
import { createUpdateSchema } from 'drizzle-orm/typebox-legacy';
import { Value } from '@sinclair/typebox/value';
import { eq } from "drizzle-orm";

const users = pgTable('users', {
  id: integer().generatedAlwaysAsIdentity().primaryKey(),
  name: text().notNull(),
  age: integer().notNull()
});

const userUpdateSchema = createUpdateSchema(users);

const user = { age: 35 };
const parsed: { name?: string | undefined, age?: number | undefined } = Value.Parse(userUpdateSchema, user); // Will parse successfully
await db.update(users).set(parsed).where(eq(users.name, 'Jane'));
```

### Refinements

Each create schema function accepts an additional optional parameter that you can used to extend, modify or completely overwite a field's schema. Defining a callback function will extend or modify while providing a Typebox schema will overwrite it.

```ts copy
import { pgTable, text, integer, json } from 'drizzle-orm/pg-core';
import { createSelectSchema } from 'drizzle-orm/typebox-legacy';
import { Type } from '@sinclair/typebox';
import { Value } from '@sinclair/typebox/value';

const users = pgTable('users', {
  id: integer().generatedAlwaysAsIdentity().primaryKey(),
  name: text().notNull(),
  bio: text(),
  preferences: json()
});

const userSelectSchema = createSelectSchema(users, {
  name: (schema) => Type.String({ ...schema, maxLength: 20 }), // Extends schema
  bio: (schema) => Type.String({ ...schema, maxLength: 1000 }), // Extends schema before becoming nullable/optional
  preferences: Type.Object({ theme: Type.String() }) // Overwrites the field, including its nullability
});

const parsed: {
  id: number;
  name: string,
  bio: string | null;
  preferences: {
    theme: string;
  };
} = Value.Parse(userSelectSchema, ...);
```

### Factory functions

For more advanced use cases, you can use the `createSchemaFactory` function.

**Use case: Using an extended Typebox instance**

```ts copy
import { pgTable, text, integer } from 'drizzle-orm/pg-core';
import { createSchemaFactory } from 'drizzle-orm/typebox';
import { t } from 'elysia'; // Extended Typebox instance

const users = pgTable('users', {
  id: integer().generatedAlwaysAsIdentity().primaryKey(),
  name: text().notNull(),
  age: integer().notNull()
});

const { createInsertSchema } = createSchemaFactory({ typeboxInstance: t });

const userInsertSchema = createInsertSchema(users, {
  // We can now use the extended instance
  name: (schema) => t.Number({ ...schema, error: "`name` must be a string" }),
});
```

### Data type reference

```ts
pg.boolean();

// Schema
Type.Boolean();
```

```ts
pgEnum('name', ['val1', 'val2']);

// Schema
Type.Enum({'val1': 'val1', 'val2': 'val2'});
```

```ts
pg.date({ mode: 'date' });
pg.timestamp({ mode: 'date' });

// Schema
Type.Date();
```

```ts
pg.date({ mode: 'string' });
pg.timestamp({ mode: 'string' });
pg.cidr();
pg.inet();
pg.interval();
pg.macaddr();
pg.macaddr8();
pg.numeric();
pg.text();
pg.sparsevec();
pg.time();

// Schema
Type.String();
```

```ts
pg.bit({ dimensions: ... });

// Schema
t.RegExp(/^[01]+$/, { maxLength: dimensions });
```

```ts
pg.uuid();

// Schema
Type.String({ format: 'uuid' });
```

```ts
pg.char({ length: ... });

// Schema
Type.String({ minLength: length, maxLength: length });
```

```ts
pg.varchar({ length: ... });

// Schema
Type.String({ maxLength: length });
```

```ts
pg.text({ enum: ... });
pg.char({ enum: ... });
pg.varchar({ enum: ... });

// Schema
Type.Enum(enum);
```

```ts
pg.smallint();
pg.smallserial();

// Schema
Type.Integer({ minimum: -32_768, maximum: 32_767 }); // 16-bit integer lower and upper limit
```

```ts
pg.real();

// Schema
Type.Number().min(-8_388_608).max(8_388_607); // 24-bit integer lower and upper limit
```

```ts
pg.integer();
pg.serial();

// Schema
Type.Integer({ minimum: -2_147_483_648, maximum: 2_147_483_647 }); // 32-bit integer lower and upper limit
```

```ts
pg.doublePrecision();

// Schema
Type.Number({ minimum: -140_737_488_355_328, maximum: 140_737_488_355_327 }); // 48-bit integer lower and upper limit
```

```ts
pg.bigint({ mode: 'number' });
pg.bigserial({ mode: 'number' });

// Schema
Type.Integer({ minimum: -9_007_199_254_740_991, maximum: 9_007_199_254_740_991 }); // Javascript min. and max. safe integers
```

```ts
pg.bigint({ mode: 'bigint' });
pg.bigserial({ mode: 'bigint' });

// Schema
Type.BigInt({ minimum: -9_223_372_036_854_775_808n, maximum: 9_223_372_036_854_775_807n }); // 64-bit integer lower and upper limit
```

```ts
pg.geometry({ type: 'point', mode: 'tuple' });
pg.point({ mode: 'tuple' });

// Schema
Type.Tuple([Type.Number(), Type.Number()]);
```

```ts
pg.geometry({ type: 'point', mode: 'xy' });
pg.point({ mode: 'xy' });

// Schema
Type.Object({ x: Type.Number(), y: Type.Number() });
```

```ts
pg.halfvec({ dimensions: ... });
pg.vector({ dimensions: ... });

// Schema
Type.Array(Type.Number(), { minItems: dimensions, maxItems: dimensions });
```

```ts
pg.line({ mode: 'abc' });

// Schema
Type.Object({ a: Type.Number(), b: Type.Number(), c: Type.Number() });
```

```ts
pg.line({ mode: 'tuple' });

// Schema
Type.Tuple([Type.Number(), Type.Number(), Type.Number()]);
```

```ts
pg.json();
pg.jsonb();

// Schema
Type.Recursive((self) => Type.Union([Type.Union([Type.String(), Type.Number(), Type.Boolean(), Type.Null()]), Type.Array(self), Type.Record(Type.String(), self)]));
```

```ts
pg.dataType().array(...);

// Schema
Type.Array(baseDataTypeSchema, { minItems: size, maxItems: size });
```

```ts
pg.bytea();

// Schema
TypeRegistry.Set('Buffer', (_, value) => value instanceof Buffer);
const bufferSchema = { [Kind]: 'Buffer', type: 'buffer' };
```


Source: https://orm.drizzle.team/docs/pg/typebox

import Npm from '@mdx/Npm.astro';
import Callout from '@mdx/Callout.astro';

# typebox

#### Install the dependencies
<Npm>
drizzle-orm@rc typebox
</Npm>

Allows you to generate [typebox](https://sinclairzx81.github.io/typebox/#/) schemas from Drizzle ORM schemas

**Features**

- Create a select schema for tables, views and enums.
- Create insert and update schemas for tables.

#### Usage

```ts
import { pgTable, serial, text, timestamp } from 'drizzle-orm/pg-core';
import { createInsertSchema, createSelectSchema, createUpdateSchema } from 'drizzle-orm/typebox';
import { Type } from 'typebox';
import { Value } from 'typebox/value';

const users = pgTable('users', {
	id: serial().primaryKey(),
	name: text().notNull(),
	email: text().notNull(),
	role: text({ enum: ['admin', 'user'] }).notNull(),
	createdAt: timestamp('created_at').notNull().defaultNow(),
});

// Schema for inserting a user - can be used to validate API requests
const insertUserSchema = createInsertSchema(users);

// Schema for updating a user - can be used to validate API requests
const updateUserSchema = createUpdateSchema(users);

// Schema for selecting a user - can be used to validate API responses
const selectUserSchema = createSelectSchema(users);

// Overriding the fields
const insertUserSchema = createInsertSchema(users, {
	role: Type.String(),
});

// Refining the fields - useful if you want to change the fields before they become nullable/optional in the final schema
const insertUserSchema = createInsertSchema(users, {
	id: (schema) => Type.Number({ ...schema, minimum: 0 }),
	role: Type.String(),
});

// Usage
const isUserValid: boolean = Value.Check(insertUserSchema, {
	name: 'John Doe',
	email: 'johndoe@test.com',
	role: 'admin',
});
```


Source: https://orm.drizzle.team/docs/pg/update

import Callout from '@mdx/Callout.astro';
import Section from '@mdx/Section.astro';

# SQL Update

<Callout type='info'>
All the values provided to `.set()`are parameterized automatically.
For example, this query:
```ts
await db.update(users).set({ name: "Mr. Dan" }).where(eq(users.name, "Dan"));
```
will be translated to:
```sql
update "users" set "name" = $1 where "users"."name" = $2; -- params: ['Mr. Dan', 'Dan']
```
</Callout>

<br/>

The object that you pass to `update` should have keys that match column names in your database schema.
Values of `undefined` are ignored in the object: to set a column to `null`, pass `null`.

```typescript copy
await db.update(users)
  .set({ name: 'Mr. Dan' })
  .where(eq(users.name, 'Dan'));
```
```typescript copy
await db.update(users)
  .set({ name: null })
  .where(eq(users.name, 'Dan'));
```

You can pass SQL as a value to be used in the update object, like this:

```typescript copy
await db.update(users)
  .set({ updatedAt: sql`NOW()` })
  .where(eq(users.name, 'Dan'));
```

### Returning

You can update a row and get it back in PostgreSQL:
```typescript copy
const updatedUserId = await db.update(users).set({ name: "Mr. Dan" }).where(eq(users.name, "Dan")).returning({ updatedId: users.id });
//      ^ { updatedId: number | null }[]
```
```sql
update "users" set "name" = 'Mr. Dan' where "users"."name" = 'Dan' returning "id";
```

## `with update` clause

<Callout>
  Check how to use WITH statement with [select](/docs/select#with-clause), [insert](/docs/insert#with-insert-clause), [delete](/docs/delete#with-delete-clause)
</Callout>

Using the `with` clause can help you simplify complex queries by splitting them into smaller subqueries called common table expressions (CTEs):
<Section>
```typescript copy
const averagePrice = db.$with('average_price').as(
	db.select({ value: sql`avg(${products.price})`.as('value') }).from(products)
);

const result = await db.with(averagePrice)
	.update(products)
	.set({
		cheap: true
	})
	.where(lt(products.price, sql`(select * from ${averagePrice})`))
	.returning({
		id: products.id
	});
```
```sql
with "average_price" as (select avg("price") as "value" from "products") 
update "products" set "cheap" = true 
where "products"."price" < (select * from "average_price") 
returning "id"
```
</Section>

## Update ... from

As PostgreSQL documentation states:

> A table expression allowing columns from other tables to appear in the WHERE condition and update expressions

<Section>
```ts
await db
  .update(users)
  .set({ cityId: cities.id })
  .from(cities)
  .where(and(eq(cities.name, 'Seattle'), eq(users.name, 'John')))
```
```sql
update "users" set "city_id" = "cities"."id" 
from "cities" 
where (("cities"."name" = 'Seattle') and ("users"."name" = 'John'))
```
</Section>

You can also alias tables that are joined (you can also alias the updating table too).
<Section>
```ts
const c = alias(cities, 'c');
await db
  .update(users)
  .set({ cityId: c.id })
  .from(c);
```
```sql
update "users" set "city_id" = "c"."id" 
from "cities" "c"
```
</Section>

In Postgres, you can also return columns from the joined tables.
<Section>
```ts
const updatedUsers = await db
  .update(users)
  .set({ cityId: cities.id })
  .from(cities)
  .returning({ id: users.id, cityName: cities.name });
```
```sql
update "users" set "city_id" = "cities"."id" 
from "cities" 
returning "users"."id", "cities"."name"
```
</Section>


Source: https://orm.drizzle.team/docs/pg/upgrade-v1

import Npm from "@mdx/Npm.astro";
import Npx from "@mdx/Npx.astro";
import Prerequisites from "@mdx/Prerequisites.astro";

# Upgrading to Drizzle v1

<Npm>
 drizzle-orm@rc
 -D drizzle-kit@rc
</Npm>

#### Step 1 - Run `drizzle-kit up`

> v3 migration folder discussion: https://github.com/drizzle-team/drizzle-orm/discussions/2832  

We've updated the migrations folder structure by:
- removing `journal.json`
- grouping SQL files and snapshots into separate migration folders
- removing the `drizzle-kit drop` command

These changes eliminate potential Git conflicts with the journal file and simplify the process of dropping or fixing conflicted migrations

The drizzle-kit has been architecturally redesigned:
- Migrated from database snapshots to DDL snapshots

Commutativity checks were added:
- Detecting non-commutative migrations across branches
> Commutativity discussion: https://github.com/drizzle-team/drizzle-orm/discussions/5005

To migrate from old structure to a new one you would need to run

<Npx>
drizzle-kit up
</Npx>

#### Step 2 - Review breaking changes

You can find out the full list of breaking changes [here](/docs/v0-v1-changes#breaking-changes) and make sure to update your code accordingly

If you were using Relational Queries, you need to upgrade to v2:
- [How to migrate relations definition from v1 to v2](/docs/relations-v1-v2#how-to-migrate-relations-schema-definition-from-v1-to-v2)
- [How to migrate queries from v1 to v2](/docs/relations-v1-v2#how-to-migrate-queries-from-v1-to-v2)

#### Step 3 - Done ✅


Source: https://orm.drizzle.team/docs/pg/v0-v1-changes

import Callout from '@mdx/Callout.astro';

# Changes in v1

This page shows everything that changed from `drizzle-orm@0.x`, `drizzle-kit@0.x`, `drizzle-seed@0.x` to the latest `drizzle-orm@1.0`, `drizzle-kit@1.0`, `drizzle-seed@1.0`

<Callout type="info">
Read more on how to upgrade [here](/docs/upgrade-v1)
</Callout>

## Breaking changes

#### Relational Queries v1 removed

RQBv1 has been removed. Use [Relational Queries v2](/docs/relations) with the new `defineRelations()` API instead and new features. You can find more details about migrating from rqb v1 to v2 [here](/docs/relations-v1-v2)

A new relations system built around `defineRelations()`:

```ts
import { defineRelations } from 'drizzle-orm';

const relations = defineRelations(schema, (r) => ({
  users: {
    posts: r.many.posts(),
    profile: r.one.profiles(),
  },
  posts: {
    author: r.one.users({
      from: posts.authorId,
      to: users.id,
    }),
  },
}));
```

#### New Casing API

The legacy `drizzle({ casing: 'camelCase' })` has been replaced with a table/view/schema-level API:

```ts
import { snakeCase, camelCase } from 'drizzle-orm/pg-core';

export const users = snakeCase.table('users', {
  id: serial().primaryKey(),
  fullName: text(),        // → full_name in DB
  createdAt: timestamp(),  // → created_at in DB
});

// Available on all entity types:
snakeCase.table / snakeCase.view / snakeCase.materializedView / snakeCase.schema
camelCase.table / camelCase.view / camelCase.materializedView / camelCase.schema
```

#### Validator packages consolidated into `drizzle-orm`

<Callout type="warning">
You can still use drizzle-zod/valibot/typebox/arktype validation packages but all new update will be added to Drizzle ORM directly
</Callout>

- drizzle-zod -> [drizzle-orm/zod](/docs/zod)
- drizzle-valibot -> [drizzle-orm/valibot](/docs/valibot)
- drizzle-typebox -> [drizzle-orm/typebox-legacy](/docs/typebox-legacy) (using @sinclair/typebox)
- drizzle-typebox -> [drizzle-orm/typebox](/docs/typebox) (using typebox)
- drizzle-arktype -> [drizzle-orm/arktype](/docs/arktype)
- new `drizzle-orm/effect-schema` package added

#### `.array()` is no longer chainable

Use string syntax for multidimensional arrays:

```ts
// ❌ Before
column.array().array()

// ✅ After
column.array('[][]')
column.array('[][][]')
```

#### `.enableRLS()` deprecated

The `.enableRLS()` method on tables has been deprecated. Use `pgTable.withRLS()` instead:

```ts
// ❌ Before
const users = pgTable('users', { ... }).enableRLS();

// ✅ After
const users = pgTable.withRLS('users', { ... });
```

#### `.generatedAlwaysAs()` only accepts SQL

```ts
// ❌ Before — accepted raw values
.generatedAlwaysAs('some expression')

// ✅ After — only sql`` or () => sql``
.generatedAlwaysAs(sql`some expression`)
.generatedAlwaysAs(() => sql`some expression`)
```

#### `getTableColumns` deprecation

Use `getColumns` instead

```ts
// ❌ Before
import { getTableColumns } from 'drizzle-orm';

const columns = getTableColumns(users);

// ✅ After
import { getColumns } from 'drizzle-orm';

const columns = getColumns(users);
```

#### New migration folder structure (v3)

**Linked discussion**: [#2832](https://github.com/drizzle-team/drizzle-orm/discussions/2832)

<br/>

- No more `journal.json`
- SQL files and snapshots grouped into separate migration folders
- `drizzle-kit drop` command removed

These changes eliminate potential Git conflicts with the journal file and simplify the process of dropping or fixing conflicted migrations

<Callout type="info">
Read more on how to upgrade [here](/docs/upgrade-v1)
</Callout>

#### `schemaFilter` default behavior changed

`drizzle-kit push` and `drizzle-kit pull` now manage **all schemas** by default, not just `public`. It also now supports glob patterns.

<Callout type='warning' title='How it worked in 0.x versions'>
In 0.x, `drizzle-kit push` and `drizzle-kit pull` managed only tables in the `public` schema by default. You had to explicitly configure `schemaFilter` to manage other schemas.
</Callout>

```ts
// ❌ Before (0.x) — only `public` by default, explicit list only
export default defineConfig({
  schemaFilter: ['public', 'analytics'],
});

// ✅ After (1.0) — all schemas by default, glob patterns supported
export default defineConfig({
  // no schemaFilter needed if you want all schemas managed
});

// To limit to specific schemas, you can still use schemaFilter:
export default defineConfig({
  schemaFilter: ['public', 'app_*'], // glob patterns supported
});
```

#### `drizzle-kit push --strict` deprecation

The `--strict` flag has been removed — its behavior is now the default. `drizzle-kit push` always prompts for confirmation for data-loss statements unless the `--force` flag is passed. Use [drizzle-kit push --explain](/docs/drizzle-kit-push) to preview the SQL that would be executed before running it.

{/* #### Drizzle seed: UUID generator upgraded to v4

The UUID generator now produces RFC 4122 v4 compliant UUIDs, ensuring compatibility with Zod v4 validation. Use `{ version: '1' }` to keep old behavior, or `{ version: '2' | '3' }` for newer generators. */}

## Other features

#### JIT Mappers (opt-in)

Just-in-time compiled row mappers that make mapping as fast as the raw driver.
You can find out more [here](/docs/jit-mappers)

```ts {1}
const db = drizzle({ ..., jit: true });
```

#### Codecs

This is a driver-aware transform layer for normalizing requests/responses to/from DB. It resolves data-mapping inconsistencies between regular select, JSON object, and array contexts.
You can find out more [here](/docs/codecs)

#### New MSSQL dialect

New MSSQL dialect support added. You can read more [here](/docs/mssql/get-started-mssql)

#### New CockroachDB dialect

New CockroachDB dialect support added. You can read more [here](/docs/cockroach/get-started-cockroach)

#### New NetlifyDB driver

New NetlifyDB driver support added. You can read more [here](/docs/connect-netlify-db)

<Callout>
Note: The Netlify Database driver is developed and maintained by the Netlify team.
</Callout>

#### Effect integration

- New **`@effect/sql-pg` driver support**. You can read more [here](/docs/connect-effect-postgres)
- **Effect Schema validation** via `drizzle-orm/effect-schema`. You can read more [here](/docs/effect-schema)

#### SQLcommenter support

Add custom tags to queries. Tags are appended as SQL comments at the end of each query. You can read more [here](/docs/sql-comments)

```ts
db.select().from(users).comment("my_first_tag");
// select "id", "name" from "users" /*my_first_tag*/
```

#### Column aliases via `.as()`

You can find out more aliasing info [here](/docs/aliases)
```ts
const query = db
  .select({ age: users.age.as('ageOfUser'), id: users.id.as('userId') })
  .from(users)
  .orderBy(asc(users.id.as('userId')));
```

#### Prepared queries

`.prepare(name)` name is now optional

#### Full `drizzle-kit` rewrite

The kit has been architecturally redesigned:
- Migrated from database snapshots to DDL snapshots
- Reworked diff detection and application
- Schema introspection reduced from ~10s to < 1s
- Added query hints and explain support for push

#### `drizzle-kit pull --init`

Creates the drizzle migration table and marks the first pulled migration as applied. You can read more [here](/docs/drizzle-kit-pull)

#### `drizzle-kit push --explain`

Shows the SQL that would be executed without actually running it. You can read more [here](/docs/drizzle-kit-push)

#### `drizzle-kit check` — commutativity check

Detects non-commutative migrations across branches — e.g., two branches altering the same column, or one renaming a table that another is altering.

How it works:
- Builds a DAG from snapshot `prevIds` to understand branch structure
- Finds fork points where branches diverged
- Computes the DDL diff from parent snapshot to each branch leaf
- Checks conflicts using a footprint map of which DDL statement types can interfere

If conflicts are found, the report tells you exactly which migrations on which branches are incompatible

#### `drizzle-kit --ignore-conflicts` flag

Bypasses commutativity checks when you know the conflicts are expected.

#### `drizzle-kit generate`: migration conflict detection

`drizzle-kit generate` now identifies [incompatible changes](/docs/v0-v1-changes#drizzle-kit-check--commutativity-check) across migration branches. Use `--ignore-conflicts` to bypass.

#### Updates to the migration table

The migration table is automatically upgraded when you run `drizzle-kit up`. Two new columns are added:

- **`name`** — the full migration folder name (e.g. `20250220153045_brave_wolverine`)
- **`applied_at`** — timestamp of when the migration was executed (pre-existing rows are backfilled with `NULL`)

| Column | Type | v0 | v1 |
| --- | --- | --- |:---:|
| `id` | serial | yes | yes |
| `hash` | text | yes | yes |
| `created_at` | bigint | yes | yes (legacy) |
| `name` | text | — | new |
| `applied_at` | timestamp with time zone | — | new |

Migrations are now matched by their full folder name instead of timestamps. Even if two migrations are generated within the same second, the name suffix guarantees uniqueness.

During the upgrade, existing rows are backfilled using a multi-step strategy:
1. **Millis match** — truncate stored millis to seconds, match against local folder timestamps
2. **Hash tiebreaker** — if multiple migrations share the same second, disambiguate via the SQL hash
3. **Hash-only fallback** — if millis matching fails entirely, match by hash alone

<br/>
This means the upgrade handles all edge cases: normal single-developer projects, teams with closely-timed migrations, and even cases where the old journal data doesn't perfectly align with the new folder names.

#### Migrator applies all missing migrations

Previously the migrator only looked for local migrations with a creation date later than the last applied one. Now it detects and applies **every missing migration**, regardless of timestamp ordering. All migrations are matched against the full folder name (14-digit UTC timestamp + name suffix).

#### Top-level `await` in drizzle config files

Top-level `await` is now supported in `drizzle.config.ts` and schema files on Node.js.

#### Drizzle-kit: Build system improvements

- Migrated from `esbuild-register` to `tsx` loader — seamless ESM and CJS support
- Native Bun and Deno launch support

#### TS Schema file processing

Only files with the following extensions are processed: `.js`, `.mjs`, `.cjs`, `.jsx`, `.ts`, `.mts`, `.cts`, `.tsx`. All other file types are ignored.

Source: https://orm.drizzle.team/docs/pg/valibot

import Npm from '@mdx/Npm.astro';
import Callout from '@mdx/Callout.astro';

# valibot

### Install the dependencies

<Npm>
drizzle-orm@rc valibot
</Npm>

### Select schema

Defines the shape of data queried from the database - can be used to validate API responses.

```ts copy
import { pgTable, text, integer } from 'drizzle-orm/pg-core';
import { createSelectSchema } from 'drizzle-orm/valibot';
import { parse } from 'valibot';

const users = pgTable('users', {
  id: integer().generatedAlwaysAsIdentity().primaryKey(),
  name: text().notNull(),
  age: integer().notNull()
});

const userSelectSchema = createSelectSchema(users);

const rows = await db.select({ id: users.id, name: users.name }).from(users).limit(1);
const parsed: { id: number; name: string; age: number } = parse(userSelectSchema, rows[0]); // Error: `age` is not returned in the above query

const rows = await db.select().from(users).limit(1);
const parsed: { id: number; name: string; age: number } = parse(userSelectSchema, rows[0]); // Will parse successfully
```

Views and enums are also supported.

```ts copy
import { pgEnum, pgView } from 'drizzle-orm/pg-core';
import { gt } from 'drizzle-orm';
import { createSelectSchema } from 'drizzle-orm/valibot';
import { parse } from 'valibot';

const roles = pgEnum('roles', ['admin', 'basic']);
const rolesSchema = createSelectSchema(roles);
const parsed: 'admin' | 'basic' = parse(rolesSchema, ...);

const usersView = pgView('users_view').as((qb) => qb.select().from(users).where(gt(users.age, 18)));
const usersViewSchema = createSelectSchema(usersView);
const parsed: { id: number; name: string; age: number } = parse(usersViewSchema, ...);
```

### Insert schema

Defines the shape of data to be inserted into the database - can be used to validate API requests.

```ts copy
import { pgTable, text, integer } from 'drizzle-orm/pg-core';
import { createInsertSchema } from 'drizzle-orm/valibot';
import { parse } from 'valibot';

const users = pgTable('users', {
  id: integer().generatedAlwaysAsIdentity().primaryKey(),
  name: text().notNull(),
  age: integer().notNull()
});

const userInsertSchema = createInsertSchema(users);

const user = { name: 'John' };
const parsed: { name: string, age: number } = parse(userInsertSchema, user); // Error: `age` is not defined

const user = { name: 'Jane', age: 30 };
const parsed: { name: string, age: number } = parse(userInsertSchema, user); // Will parse successfully
await db.insert(users).values(parsed);
```

### Update schema

Defines the shape of data to be updated in the database - can be used to validate API requests.

```ts copy
import { pgTable, text, integer } from 'drizzle-orm/pg-core';
import { createUpdateSchema } from 'drizzle-orm/valibot';
import { parse } from 'valibot';

const users = pgTable('users', {
  id: integer().generatedAlwaysAsIdentity().primaryKey(),
  name: text().notNull(),
  age: integer().notNull()
});

const userUpdateSchema = createUpdateSchema(users);

const user = { age: 35 };
const parsed: { name?: string | undefined, age?: number | undefined } = parse(userUpdateSchema, user); // Will parse successfully
await db.update(users).set(parsed).where(eq(users.name, 'Jane'));
```

### Refinements

Each create schema function accepts an additional optional parameter that you can used to extend, modify or completely overwite a field's schema. Defining a callback function will extend or modify while providing a Valibot schema will overwrite it.

```ts copy
import { pgTable, text, integer, json } from 'drizzle-orm/pg-core';
import { createSelectSchema } from 'drizzle-orm/valibot';
import { parse, pipe, maxLength, object, string } from 'valibot';

const users = pgTable('users', {
  id: integer().generatedAlwaysAsIdentity().primaryKey(),
  name: text().notNull(),
  bio: text(),
  preferences: json()
});

const userSelectSchema = createSelectSchema(users, {
  name: (schema) => pipe(schema, maxLength(20)), // Extends schema
  bio: (schema) => pipe(schema, maxLength(1000)), // Extends schema before becoming nullable/optional
  preferences: object({ theme: string() }) // Overwrites the field, including its nullability
});

const parsed: {
  id: number;
  name: string;
  bio: string | null;
  preferences: {
      theme: string;
  };
} = parse(userSelectSchema, ...);
```

### Data type reference

```ts
pg.boolean();

// Schema
boolean();
```

```ts
pgEnum('name', ['val1', 'val2']);

// Schema
enum({ val1: "val1", val2: "val2" });
```

```ts
pg.date({ mode: 'date' });
pg.timestamp({ mode: 'date' });

// Schema
date();
```

```ts
pg.date({ mode: 'string' });
pg.timestamp({ mode: 'string' });
pg.cidr();
pg.inet();
pg.interval();
pg.macaddr();
pg.macaddr8();
pg.numeric();
pg.text();
pg.sparsevec();
pg.time();

// Schema
string();
```

```ts
pg.bit({ dimensions: ... });

// Schema
pipe(string(), regex(/^[01]+$/), maxLength(dimensions));
```

```ts
pg.uuid();

// Schema
pipe(string(), uuid());
```

```ts
pg.char({ length: ... });

// Schema
pipe(string(), length(length));
```

```ts
pg.varchar({ length: ... });

// Schema
pipe(string(), maxLength(length));
```

```ts
pg.text({ enum: ... });
pg.char({ enum: ... });
pg.varchar({ enum: ... });

// Schema
enum(enum);
```

```ts
pg.smallint();
pg.smallserial();

// Schema
pipe(number(), minValue(-32_768), maxValue(32_767), integer()); // 16-bit integer lower and upper limit
```

```ts
pg.real();

// Schema
pipe(number(), minValue(-8_388_608), maxValue(8_388_607)); // 24-bit integer lower and upper limit
```

```ts
pg.integer();
pg.serial();

// Schema
pipe(number(), minValue(-2_147_483_648), maxValue(2_147_483_647), integer()); // 32-bit integer lower and upper limit
```

```ts
pg.doublePrecision();

// Schema
pipe(number(), minValue(-140_737_488_355_328), maxValue(140_737_488_355_327)); // 48-bit integer lower and upper limit
```

```ts
pg.bigint({ mode: 'number' });
pg.bigserial({ mode: 'number' });

// Schema
pipe(number(), minValue(-9_007_199_254_740_991), maxValue(9_007_199_254_740_991), integer()); // Javascript min. and max. safe integers
```

```ts
pg.bigint({ mode: 'bigint' });
pg.bigserial({ mode: 'bigint' });

// Schema
pipe(bigint(), minValue(-9_223_372_036_854_775_808n), maxValue(9_223_372_036_854_775_807n)); // 64-bit integer lower and upper limit
```

```ts
pg.geometry({ type: 'point', mode: 'tuple' });
pg.point({ mode: 'tuple' });

// Schema
tuple([number(), number()]);
```

```ts
pg.geometry({ type: 'point', mode: 'xy' });
pg.point({ mode: 'xy' });

// Schema
object({ x: number(), y: number() });
```

```ts
pg.halfvec({ dimensions: ... });
pg.vector({ dimensions: ... });

// Schema
pipe(array(number()), length(dimensions));
```

```ts
pg.line({ mode: 'abc' });

// Schema
object({ a: number(), b: number(), c: number() });
```

```ts
pg.line({ mode: 'tuple' });

// Schema
tuple([number(), number(), number()]);
```

```ts
pg.json();
pg.jsonb();

// Schema
union([union([string(), number(), boolean(), null_()]), array(any()), record(string(), any())]);
```

```ts
pg.dataType().array(...);

// Schema
pipe(array(baseDataTypeSchema), length(size));
```

```ts
pg.bytea();

// Schema
custom<Buffer>((v) => v instanceof Buffer)
```


Source: https://orm.drizzle.team/docs/pg/views

import Callout from '@mdx/Callout.astro';
import Section from '@mdx/Section.astro';

# Views

There're several ways you can declare views with Drizzle ORM.  

You can declare views that have to be created or you can declare views that already exist in the database. 

You can declare views statements with an inline `query builder` syntax, with `standalone query builder` and with raw `sql` operators. 

When views are created with either inlined or standalone query builders, view columns schema will be automatically inferred, 
yet when you use `sql` you have to explicitly declare view columns schema.

### Declaring views

<Section>
      ```ts filename="schema.ts" copy {14-15}
      import { pgTable, pgView, serial, text, timestamp } from "drizzle-orm/pg-core";
      import { eq } from "drizzle-orm";

      export const user = pgTable("user", {
        id: serial(),
        name: text(),
        email: text(),
        password: text(),
        role: text().$type<"admin" | "customer">(),
        createdAt: timestamp("created_at"),
        updatedAt: timestamp("updated_at"),
      });

      export const userView = pgView("user_view").as((qb) => qb.select().from(user));
      export const customersView = pgView("customers_view").as((qb) => qb.select().from(user).where(eq(user.role, "customer")));
      ```
      ```sql
      CREATE VIEW "user_view" AS (SELECT * FROM "user");
      CREATE VIEW "customers_view" AS (SELECT * FROM "user" WHERE "role" = 'customer');
      ```
    </Section>

You can also declare views using `standalone query builder`, it works exactly the same way:

<Section>
      ```ts filename="schema.ts" copy {4,16-17}
      import { pgTable, pgView, serial, text, timestamp, QueryBuilder} from "drizzle-orm/pg-core";
      import { eq } from "drizzle-orm";

      const qb = new QueryBuilder();

      export const user = pgTable("user", {
        id: serial(),
        name: text(),
        email: text(),
        password: text(),
        role: text().$type<"admin" | "customer">(),
        createdAt: timestamp("created_at"),
        updatedAt: timestamp("updated_at"),
      });

      export const userView = pgView("user_view").as(qb.select().from(user));
      export const customersView = pgView("customers_view").as(qb.select().from(user).where(eq(user.role, "customer")));
      ```
      ```sql
      CREATE VIEW "user_view" AS (SELECT * FROM "user");
      CREATE VIEW "customers_view" AS (SELECT * FROM "user" WHERE "role" = 'customer');
      ```
    </Section>

### Declaring views with raw SQL
Whenever you need to declare view using a syntax that is not supported by the query builder, 
you can directly use `sql` operator and explicitly specify view columns schema.

```ts copy
// regular view
export const newYorkers = pgView('new_yorkers', {
  id: serial('id').primaryKey(),
  name: text('name').notNull(),
  cityId: integer('city_id').notNull(),
}).as(sql`select * from ${users} where ${eq(users.cityId, 1)}`);

// materialized view
export const newYorkers = pgMaterializedView('new_yorkers', {
  id: serial('id').primaryKey(),
  name: text('name').notNull(),
  cityId: integer('city_id').notNull(),
}).as(sql`select * from ${users} where ${eq(users.cityId, 1)}`);
```

### Declaring existing views
When you're provided with a read only access to an existing view in the database you should use `.existing()` view configuration, 
`drizzle-kit` will ignore and will not generate a `create view` statement in the generated migration.
```ts {16,23}
export const user = pgTable("user", {
  id: serial(),
  name: text(),
  email: text(),
  password: text(),
  role: text().$type<"admin" | "customer">(),
  createdAt: timestamp("created_at"),
  updatedAt: timestamp("updated_at"),
});

// regular view
export const trimmedUser = pgView("trimmed_user", {
  id: serial("id"),
  name: text("name"),
  email: text("email"),
}).existing();

// materialized view won't make any difference, yet you can use it for consistency
export const trimmedUser = pgMaterializedView("trimmed_user", {
  id: serial("id"),
  name: text("name"),
  email: text("email"),
}).existing();
```

### Materialized views

According to the official docs, PostgreSQL and CockroachDB have both **[`regular`](https://www.postgresql.org/docs/current/sql-createview.html)**
and **[`materialized`](https://www.postgresql.org/docs/current/sql-creatematerializedview.html)** views.
  
Materialized views in PostgreSQL and CockroachDB use the rule system like views do, but persist the results in a table-like form.
{/* This means that when a query is executed against a materialized view, the results are returned directly from the materialized view,
like from a table, rather than being reconstructed by executing the query against the underlying base tables that make up the view. */}

<Section>
```ts filename="schema.ts" copy
export const newYorkers = pgMaterializedView('new_yorkers').as((qb) => qb.select().from(users).where(eq(users.cityId, 1)));
```
```sql
CREATE MATERIALIZED VIEW "new_yorkers" AS (SELECT * FROM "users");
```
</Section>

You can then refresh materialized views in the application runtime:
```ts copy
await db.refreshMaterializedView(newYorkers);

await db.refreshMaterializedView(newYorkers).concurrently();

await db.refreshMaterializedView(newYorkers).withNoData();
```

### Extended example
<Callout type="info" emoji="ℹ️">
All the parameters inside the query will be inlined, instead of replaced by `$1`, `$2`, etc.
</Callout>

```ts copy
// regular view
export const newYorkers = pgView('new_yorkers')
  .with({
    checkOption: 'cascaded',
    securityBarrier: true,
    securityInvoker: true,
  })
  .as((qb) => {
    const sq = qb
      .$with('sq')
      .as(
        qb.select({ userId: users.id.as("user_id"), cityId: cities.id.as("city_id"), homeCity: users.homeCity })
          .from(users)
          .leftJoin(cities, eq(cities.id, users.homeCity))
          .where(sql`${users.age1} > 18`),
      );
    return qb.with(sq).select().from(sq).where(sql`${sq.homeCity} = 1`);
  });

// materialized view
export const newYorkers2 = pgMaterializedView('new_yorkers_2')
  .using('heap')
  .with({
    fillfactor: 90,
    toastTupleTarget: 0.5,
    autovacuumEnabled: true,
    ...
  })
  .tablespace('custom_tablespace')
  .withNoData()
  .as((qb) => {
    const sq = qb
      .$with('sq')
      .as(
        qb.select({ userId: users.id.as("user_id"), cityId: cities.id.as("city_id"), homeCity: users.homeCity })
          .from(users)
          .leftJoin(cities, eq(cities.id, users.homeCity))
          .where(sql`${users.age1} > 18`),
      );
    return qb.with(sq).select().from(sq).where(sql`${sq.homeCity} = 1`);
  });
```
```sql
...

CREATE VIEW "new_yorkers"
WITH
	(check_option = cascaded, security_barrier = TRUE, security_invoker = TRUE) AS (
		WITH
			"sq" AS (
				SELECT
					"user"."id" AS "user_id",
					"cities"."id" AS "city_id",
					"user"."homeCity"
				FROM
					"user"
					LEFT JOIN "cities" ON "cities"."id" = "user"."homeCity"
				WHERE
					"user"."age1" > 18
			)
		SELECT
			"user_id",
			"city_id",
			"homeCity"
		FROM
			"sq"
		WHERE
			"sq"."homeCity" = 1
	);

CREATE MATERIALIZED VIEW "new_yorkers_2" USING "heap"
WITH
	(autovacuum_enabled = TRUE, fillfactor = 90, toast_tuple_target = 0.5) TABLESPACE custom_tablespace AS (
		WITH
			"sq" AS (
				SELECT
					"user"."id" AS "user_id",
					"cities"."id" AS "city_id",
					"user"."homeCity"
				FROM
					"user"
					LEFT JOIN "cities" ON "cities"."id" = "user"."homeCity"
				WHERE
					"user"."age1" > 18
			)
		SELECT
			"user_id",
			"city_id",
			"homeCity"
		FROM
			"sq"
		WHERE
			"sq"."homeCity" = 1
	)
WITH
	NO DATA;
```


Source: https://orm.drizzle.team/docs/pg/zod

import Npm from '@mdx/Npm.astro';
import Callout from '@mdx/Callout.astro';

# zod

### Install the dependencies

<Npm>
drizzle-orm@rc zod
</Npm>

### Select schema

Defines the shape of data queried from the database - can be used to validate API responses.

```ts copy
import { pgTable, text, integer } from 'drizzle-orm/pg-core';
import { createSelectSchema } from 'drizzle-orm/zod';

const users = pgTable('users', {
  id: integer().generatedAlwaysAsIdentity().primaryKey(),
  name: text().notNull(),
  age: integer().notNull()
});

const userSelectSchema = createSelectSchema(users);

const rows = await db.select({ id: users.id, name: users.name }).from(users).limit(1);
const parsed: { id: number; name: string; age: number } = userSelectSchema.parse(rows[0]); // Error: `age` is not returned in the above query

const rows = await db.select().from(users).limit(1);
const parsed: { id: number; name: string; age: number } = userSelectSchema.parse(rows[0]); // Will parse successfully
```

Views and enums are also supported.

```ts copy
import { pgEnum, pgView } from 'drizzle-orm/pg-core';
import { gt } from 'drizzle-orm';
import { createSelectSchema } from 'drizzle-orm/zod';

const roles = pgEnum('roles', ['admin', 'basic']);
const rolesSchema = createSelectSchema(roles);
const parsed: 'admin' | 'basic' = rolesSchema.parse(...);

const usersView = pgView('users_view').as((qb) => qb.select().from(users).where(gt(users.age, 18)));
const usersViewSchema = createSelectSchema(usersView);
const parsed: { id: number; name: string; age: number } = usersViewSchema.parse(...);
```

### Insert schema

Defines the shape of data to be inserted into the database - can be used to validate API requests.

```ts copy
import { pgTable, text, integer } from 'drizzle-orm/pg-core';
import { createInsertSchema } from 'drizzle-orm/zod';

const users = pgTable('users', {
  id: integer().generatedAlwaysAsIdentity().primaryKey(),
  name: text().notNull(),
  age: integer().notNull()
});

const userInsertSchema = createInsertSchema(users);

const user = { name: 'John' };
const parsed: { name: string, age: number } = userInsertSchema.parse(user); // Error: `age` is not defined

const user = { name: 'Jane', age: 30 };
const parsed: { name: string, age: number } = userInsertSchema.parse(user); // Will parse successfully
await db.insert(users).values(parsed);
```

### Update schema

Defines the shape of data to be updated in the database - can be used to validate API requests.

```ts copy
import { pgTable, text, integer } from 'drizzle-orm/pg-core';
import { createUpdateSchema } from 'drizzle-orm/zod';
import { eq } from "drizzle-orm";

const users = pgTable('users', {
  id: integer().generatedAlwaysAsIdentity().primaryKey(),
  name: text().notNull(),
  age: integer().notNull()
});

const userUpdateSchema = createUpdateSchema(users);

const user = { age: 35 };
const parsed: { name?: string | undefined, age?: number | undefined } = userUpdateSchema.parse(user); // Will parse successfully
await db.update(users).set(parsed).where(eq(users.name, 'Jane'));
```

### Refinements

Each create schema function accepts an additional optional parameter that you can used to extend, modify or completely overwite a field's schema. Defining a callback function will extend or modify while providing a Zod schema will overwrite it.

```ts copy
import { pgTable, text, integer, json } from 'drizzle-orm/pg-core';
import { createSelectSchema } from 'drizzle-orm/zod';
import { z } from 'zod/v4';

const users = pgTable('users', {
  id: integer().primaryKey(),
  name: text().notNull(),
  bio: text(),
  preferences: json()
});

const userSelectSchema = createSelectSchema(users, {
  name: (schema) => schema.max(20), // Extends schema
  bio: (schema) => schema.max(1000), // Extends schema before becoming nullable/optional
  preferences: z.object({ theme: z.string() }) // Overwrites the field, including its nullability
});

const parsed: {
    id: number;
    name: string;
    bio: string | null;
    preferences: {
        theme: string;
    };
} = userSelectSchema.parse(...);
```

### Factory functions

For more advanced use cases, you can use the `createSchemaFactory` function.

**Use case: Using an extended Zod instance**

```ts copy
import { pgTable, text, integer } from 'drizzle-orm/pg-core';
import { createSchemaFactory } from 'drizzle-orm/zod';
import { z } from '@hono/zod-openapi'; // Extended Zod instance

const users = pgTable('users', {
  id: integer().generatedAlwaysAsIdentity().primaryKey(),
  name: text().notNull(),
  age: integer().notNull()
});

const { createInsertSchema } = createSchemaFactory({ zodInstance: z });

const userInsertSchema = createInsertSchema(users, {
  // We can now use the extended instance
  name: (schema) => schema.openapi({ example: 'John' })
});
```

**Use case: Type coercion**

```ts copy
import { pgTable, timestamp } from 'drizzle-orm/pg-core';
import { createSchemaFactory } from 'drizzle-orm/zod';
import { z } from 'zod/v4';

const users = pgTable('users', {
  ...,
  createdAt: timestamp().notNull()
});

const { createInsertSchema } = createSchemaFactory({
  // This configuration will only coerce dates. Set `coerce` to `true` to coerce all data types or specify others
  coerce: {
    date: true
  }
});

const userInsertSchema = createInsertSchema(users);
// The above is the same as this:
const userInsertSchema = z.object({
  ...,
  createdAt: z.coerce.date()
});
```

### Data type reference

```ts
pg.boolean();

// Schema
z.boolean();
```

```ts
pg.pgEnum('name', ['val1', 'val2']);

// Schema
z.enum(['val1', 'val2']);
```

```ts
pg.date({ mode: 'date' });
pg.timestamp({ mode: 'date' });

// Schema
z.date();
```

```ts
pg.date({ mode: 'string' });
pg.timestamp({ mode: 'string' });
pg.cidr();
pg.inet();
pg.interval();
pg.macaddr();
pg.macaddr8();
pg.numeric();
pg.text();
pg.sparsevec();
pg.time();

// Schema
z.string();
```

```ts
pg.bit({ dimensions: ... });

// Schema
z.string().regex(/^[01]+$/).max(dimensions);
```

```ts
pg.uuid();

// Schema
z.string().uuid();
```

```ts
pg.char({ length: ... });

// Schema
z.string().length(length);
```

```ts
pg.varchar({ length: ... });

// Schema
z.string().max(length);
```

```ts
pg.text({ enum: ... });
pg.char({ enum: ... });
pg.varchar({ enum: ... });

// Schema
z.enum(enum);
```

```ts
pg.smallint();
pg.smallserial();

// Schema
z.number().min(-32_768).max(32_767).int(); // 16-bit integer lower and upper limit
```

```ts
pg.real();

// Schema
z.number().min(-8_388_608).max(8_388_607); // 24-bit integer lower and upper limit
```

```ts
pg.integer();
pg.serial();

// Schema
z.number().min(-2_147_483_648).max(2_147_483_647).int(); // 32-bit integer lower and upper limit
```

```ts
pg.doublePrecision();

// Schema
z.number().min(-140_737_488_355_328).max(140_737_488_355_327); // 48-bit integer lower and upper limit
```

```ts
pg.bigint({ mode: 'number' });
pg.bigserial({ mode: 'number' });

// Schema
z.number().min(-9_007_199_254_740_991).max(9_007_199_254_740_991).int(); // Javascript min. and max. safe integers
```

```ts
pg.bigint({ mode: 'bigint' });
pg.bigserial({ mode: 'bigint' });

// Schema
z.bigint().min(-9_223_372_036_854_775_808n).max(9_223_372_036_854_775_807n); // 64-bit integer lower and upper limit
```

```ts
pg.geometry({ type: 'point', mode: 'tuple' });
pg.point({ mode: 'tuple' });

// Schema
z.tuple([z.number(), z.number()]);
```

```ts
pg.geometry({ type: 'point', mode: 'xy' });
pg.point({ mode: 'xy' });

// Schema
z.object({ x: z.number(), y: z.number() });
```

```ts
pg.halfvec({ dimensions: ... });
pg.vector({ dimensions: ... });

// Schema
z.array(z.number()).length(dimensions);
```

```ts
pg.line({ mode: 'abc' });

// Schema
z.object({ a: z.number(), b: z.number(), c: z.number() });
```

```ts
pg.line({ mode: 'tuple' });

// Schema
z.tuple([z.number(), z.number(), z.number()]);
```

```ts
pg.json();
pg.jsonb();

// Schema
z.union([z.union([z.string(), z.number(), z.boolean(), z.null()]), z.record(z.any()), z.array(z.any())]);
```

```ts
pg.dataType().array(...);

// Schema
z.array(baseDataTypeSchema).length(size);
```

```ts
pg.bytea();

// Schema
zod.custom<Buffer>((v) => v instanceof Buffer)
```


Source: https://orm.drizzle.team/docs/quick

import Npm from "@mdx/Npm.astro";

# Quick start
Lets build a quick start app with `PostgreSQL` + `postgresjs` and run our first migration.

The first thing we need to do is to install `drizzle-orm` and `drizzle-kit`:

<Npm>
drizzle-orm@rc postgres
-D drizzle-kit@rc
</Npm>

Lets declare our `schema.ts`:

```plaintext {4}
📦 <project root>
 ├ ...
 ├ 📂 src
 │ └ 📜 schema.ts
 └ 📜 package.json
```
```ts copy filename="schema.ts"
import { serial, text, timestamp, pgTable } from "drizzle-orm/pg-core";

export const user = pgTable("user", {
  id: serial("id"),
  name: text("name"),
  email: text("email"),
  password: text("password"),
  role: text("role").$type<"admin" | "customer">(),
  createdAt: timestamp("created_at"),
  updatedAt: timestamp("updated_at"),
});
```

Now lets add drizzle configuration file:
```plaintext {4}
📦 <project root>
 ├ ...
 ├ 📂 src
 ├ 📜 drizzle.config.ts
 └ 📜 package.json
```
```ts
import { defineConfig } from "drizzle-kit";

export default defineConfig({
  dialect: "postgresql",
  schema: "./src/schema.ts",
  out: "./drizzle",
});
```

Add `generate` and `migrate` commands to `package.json` and run our first migrations generation:

```json filename="package.json" {5,6}
{
  "name": "first time?",
  "version": "0.0.1",
  "scripts": {
    "generate": "drizzle-kit generate",
    "migrate": "drizzle-kit migrate"
  }, 
}
```
```shell filename="terminal"
$ npm run generate
...

[✓] Your SQL migration file ➜ drizzle/20242409125510_pale_mister_fear/migration.sql 🚀
```

Done! We now have our first SQL migration file 🥳
```plaintext {4}
📦 <project root>
 ├ 📂 drizzle
 │ ├ 📂 20242409125510_pale_mister_fear
 ├ 📂 src
 ├ 📜 drizzle.config.ts
 └ 📜 package.json
```
Now lets run our first migration to the database:

```shell filename="terminal"
$ npm run migrate
```

That's it, folks!  

**My personal congratulations 🎉**

Source: https://orm.drizzle.team/docs/relations-schema-declaration

import Tab from '@mdx/Tab.astro';
import Tabs from '@mdx/Tabs.astro';
import Callout from '@mdx/Callout.astro';
import SimpleLinkCards from '@mdx/SimpleLinkCards.astro';
import CodeTabs from "@mdx/CodeTabs.astro";
import Section from '@mdx/Section.astro';
import Flex from "@mdx/Flex.astro"
import LinksList from "@mdx/LinksList.astro"

# Drizzle Relations Fundamentals

In the world of databases, especially relational databases, the concept of relations is absolutely fundamental.
Think of "relations" as the connections and links between different pieces of data. Just like in real life, 
where people have relationships with each other, or objects are related to categories, databases use relations to model how different 
types of information are connected and work together.

### Normalization
Normalization is the process of organizing data in your database to reduce redundancy (duplication) and improve data integrity 
(accuracy and consistency). Think of it like tidying up a messy filing cabinet. Instead of having all sorts of papers 
crammed into one folder, you organize them into logical folders and categories to make everything easier to find and manage.

<Callout collapsed="Why is Normalization Important?">
- **Reduces Data Redundancy**: Imagine storing a customer's address every time they place an order. If the address changes, you'd have to update it in multiple places! Normalization helps you store information in one place and refer to it from other places, minimizing repetition.
- **Improves Data Integrity**: Less redundancy means less chance of inconsistencies. If you update an address in one place, it's updated everywhere it's needed.
- **Prevents Anomalies**: Normalization helps prevent issues like:
  1. **Insertion Anomalies**: Difficulty adding new data because you're missing related information.
  2. **Update Anomalies**: Having to update the same information in multiple rows.
  3. **Deletion Anomalies**: Accidentally losing valuable information when you delete something seemingly unrelated.
- **Easier to Understand and Maintain**: A normalized database is generally more logically structured and easier to understand, query, and modify.
</Callout>

Normalization is often described in terms of "normal forms" (1NF, 2NF, 3NF, and beyond). While the details can get quite technical, the core ideas are straightforward:

#### 1NF (First Normal Form): `Atomic Values`

**Goal**: Each column should hold a single, indivisible value. No repeating groups of data within a single cell

**Example**: Instead of having a single `address` column that stores `123 Main St, City, USA`, you'd 
break it down into separate columns: `street_address`, `city`, `state`, `zip_code`.

```sql
-- Unnormalized (violates 1NF)
CREATE TABLE Customers_Unnormalized (
    customer_id INT PRIMARY KEY,
    name VARCHAR(255),
    address VARCHAR(255) -- Problem: Multiple pieces of info in one column
);

-- Normalized to 1NF
CREATE TABLE Customers_1NF (
    customer_id INT PRIMARY KEY,
    name VARCHAR(255),
    street_address VARCHAR(255),
    city VARCHAR(255),
    state VARCHAR(255),
    zip_code VARCHAR(10)
);
```

#### 2NF (Second Normal Form): `Eliminate Redundant Data Dependent on Part of the Key`

**Goal**: Applies when you have a table with a composite primary key (a primary key made up of two or more columns). 
2NF ensures that all non-key attributes are fully dependent on the entire composite primary key, not just part of it.

Imagine we have a table called `order_items`. This table tracks items within orders, and we use a composite primary key (`order_id`, `product_id`) 
because a single order can have multiple of the same product (though in this simplified example, let's assume each product appears only 
once per order for clarity, but the composite key logic still applies).

<Callout collapsed="Expand for visual example">
```sql
CREATE TABLE OrderItems_Unnormalized (
    order_id INT,
    product_id VARCHAR(10),
    product_name VARCHAR(100),
    product_price DECIMAL(10, 2),
    quantity INT,
    order_date DATE,
    PRIMARY KEY (order_id, product_id) -- Composite Primary Key
);

INSERT INTO OrderItems_Unnormalized (order_id, product_id, product_name, product_price, quantity, order_date) VALUES
(101, 'A123', 'Laptop', 1200.00, 1, '2023-10-27'),
(101, 'B456', 'Mouse', 25.00, 2, '2023-10-27'),
(102, 'A123', 'Laptop', 1200.00, 1, '2023-10-28'),
(103, 'C789', 'Keyboard', 75.00, 1, '2023-10-29');
```
```
+------------------------------------------------------------------------------------+
| OrderItems_Unnormalized                                                            |
+------------------------------------------------------------------------------------+
| PK (order_id, product_id) | product_name | product_price | quantity | order_date   |
+------------------------------------------------------------------------------------+
| 101, A123               | Laptop       | 1200.00       | 1        | 2023-10-27     |
| 101, B456               | Mouse        | 25.00         | 2        | 2023-10-27     |
| 102, A123               | Laptop       | 1200.00       | 1        | 2023-10-28     |
| 103, C789               | Keyboard     | 75.00         | 1        | 2023-10-29     |
+------------------------------------------------------------------------------------+
```
</Callout>

**Problem**: Notice that `product_name` and `product_price` are repeated whenever the same `product_id` appears in different orders. 
These attributes are only dependent on `product_id`, which is part of the composite primary key (`order_id`, `product_id`), but not the entire key. 
This is a partial dependency.

To achieve 2NF, we need to remove the partially dependent attributes (`product_name`, `product_price`) and place them in a separate table where they are 
fully dependent on the primary key of that new table.

<Callout collapsed="Normalization to 2NF: Visual explanation">
```
+-------------------+     1:M     +---------------------------+
| Products          | <---------- | OrderItems_2NF            |
+-------------------+             +---------------------------+
| PK product_id     |             | PK (order_id, product_id) |
| product_name      |             | quantity                  |
| product_price     |             | order_date                |
+-------------------+             | FK product_id             |
                                  +---------------------------+
```
```sql
CREATE TABLE Products (
    product_id VARCHAR(10) PRIMARY KEY,
    product_name VARCHAR(100),
    product_price DECIMAL(10, 2)
);

CREATE TABLE OrderItems_2NF (
    order_id INT,
    product_id VARCHAR(10),
    quantity INT,
    order_date DATE,
    PRIMARY KEY (order_id, product_id), -- Composite Primary Key remains
    FOREIGN KEY (product_id) REFERENCES Products(product_id) -- Foreign Key to Products
);

-- Insert data into Products
INSERT INTO Products (product_id, product_name, product_price) VALUES
('A123', 'Laptop', 1200.00),
('B456', 'Mouse', 25.00),
('C789', 'Keyboard', 75.00);

-- Insert data into OrderItems_2NF (referencing Products)
INSERT INTO OrderItems_2NF (order_id, product_id, quantity, order_date) VALUES
(101, 'A123', 1, '2023-10-27'),
(101, 'B456', 2, '2023-10-27'),
(102, 'A123', 1, '2023-10-28'),
(103, 'C789', 1, '2023-10-29');
```
</Callout>

#### 3NF (Third Normal Form): `Eliminate Redundant Data Dependent on Non-Key Attributes`

**Goal**: Remove data that is dependent on other non-key attributes. This is about eliminating transitive dependencies.

**Problem**: Let's say we have a `suppliers` table. We store supplier information, including their `zip_code`, `city`, and `state`. `supplier_id` is the primary key.

<Callout collapsed="">
```sql
CREATE TABLE suppliers (
    supplier_id VARCHAR(10) PRIMARY KEY,
    supplier_name VARCHAR(255),
    zip_code VARCHAR(10),
    city VARCHAR(100),
    state VARCHAR(50)
);

INSERT INTO suppliers (supplier_id, supplier_name, zip_code, city, state) VALUES
('S1', 'Acme Corp', '12345', 'Anytown', 'NY'),
('S2', 'Beta Inc', '67890', 'Otherville', 'CA'),
('S3', 'Gamma Ltd', '12345', 'Anytown', 'NY');
```
```
+---------------------------------------------------------------+
| suppliers                                                     |
+---------------------------------------------------------------+
| PK supplier_id | supplier_name | zip_code | city      | state |
+---------------------------------------------------------------+
| S1             | Acme Corp     | 12345    | Anytown    | NY   |
| S2             | Beta Inc      | 67890    | Otherville | CA   |
| S3             | Gamma Ltd     | 12345    | Anytown    | NY   |
+---------------------------------------------------------------+
```
</Callout>

**Solution**: To achieve 3NF, we remove the attributes dependent on the non-key attribute (`city`, `state` dependent on `zip_code`) and put 
them into a separate table keyed by the non-key attribute itself (`zip_code`).

<Callout collapsed="Normalization to 3NF: Visual explanation">
```
+-------------------+     1:M     +--------------------+
| zip_codes         | <---------- | suppliers          |
+-------------------+             +--------------------+
| PK zip_code       |             | PK supplier_id     |
| city              |             | supplier_name      |
| state             |             | FK zip_code        |
+-------------------+             +--------------------+
```
```sql
CREATE TABLE zip_codes (
    zip_code VARCHAR(10) PRIMARY KEY,
    city VARCHAR(100),
    state VARCHAR(50)
);

CREATE TABLE suppliers (
    supplier_id VARCHAR(10) PRIMARY KEY,
    supplier_name VARCHAR(255),
    zip_code VARCHAR(10), -- Foreign Key to zip_codes
    FOREIGN KEY (zip_code) REFERENCES zip_codes(zip_code)
);

-- Insert data into zip_codes
INSERT INTO zip_codes (zip_code, city, state) VALUES
('12345', 'Anytown', 'NY'),
('67890', 'Otherville', 'CA');

-- Insert data into suppliers (referencing zip_codes)
INSERT INTO suppliers (supplier_id, supplier_name, zip_code) VALUES
('S1', 'Acme Corp', '12345'),
('S2', 'Beta Inc', '67890'),
('S3', 'Gamma Ltd', '12345');
```
</Callout>

<Callout title="Good to know">
There are additional normal forms, such as `4NF`, `5NF`, `6NF`, `EKNF`, `ETNF`, and `DKNF`. We won't cover these here, but we will create a 
dedicated set of tutorials for them in our guides and tutorials section.
</Callout>

### Database Relationships
#### One-to-One

In a one-to-one relationship, each record in `table A` is related to at most one record in `table B`, and each record in `table B` is
related to at most one record in `table A`. It's a very direct, exclusive pairing.

<Callout collapsed="Use Cases & Examples">
1. **User Profiles and User Account Details**: Think of a website. Each user account (in a Users table) might have exactly one user profile (in a UserProfiles table) containing more detailed information.
2. **Employees and Parking Spaces**: An Employees table and a ParkingSpaces table. Each employee might be assigned at most one parking space, and each parking space is assigned to at most one employee.
3. **Splitting Tables for Organization**: Sometimes, you might split a very wide table into two for better organization or security reasons, maintaining a 1-1 relationship between them.

```
Table A (One Side)      Table B (One Side)
+---------+             +---------+
| PK (A)  | <---------> | FK (A)  | (Foreign Key referencing Table A)
| ...     |             | ...     |
+---------+             +---------+
```
</Callout>


#### One-to-Many

In a one-to-many relationship, one record in `table A` can be related to many records in `table B`, but each 
record in `table B` is related to at most one record in `table A`. Think of it as a "parent-child" relationship.

<Callout collapsed="Use Cases & Examples">
1. **Customers and Orders**: One customer can place many orders, but each order belongs to only one customer.
2. **Authors and Books**: One author can write many books, but (let's simplify for now and say) each book is written by one primary author.
3. **Departments and Employees**: One department can have many employees, but each employee belongs to only one department.

```
Table A (One Side)      Table B (Many Side)
+---------+             +---------+
| PK (A)  | ----------> | FK (A)  | (Foreign Key referencing Table A)
| ...     |             | ...     |
+---------+             +---------+
     (One)                  (Many)
```
</Callout>

#### Many-to-Many

In a many-to-many relationship, one record in `table A` can be related to many records in `table B`, and one 
record in `table B` can be related to many records in `table A`. It's a more complex, bidirectional relationship.

<Callout collapsed="Use Cases & Examples">
1. **Students and Courses**: One student can enroll in many courses, and one course can have many students enrolled.
2. **Products and Categories**: One product can belong to multiple categories (e.g., a "T-shirt" can be
in "Clothing" and "Summer Wear" categories), and one category can contain many products.
3. **Authors and Books**: A book can be written by multiple authors, and an author can write multiple books.

```
Table A (Many Side)    Junction Table      Table B (Many Side)
+---------+          +-------------+     +---------+
| PK (A)  | -------->| FK (A)      | <----| FK (B)  |
| ...     |          | FK (B)      |     | ...     |
+---------+          +-------------+     +---------+
     (Many)             (Junction)          (Many)
```
</Callout>

Many-to-many relationships are not directly implemented with foreign keys between the two main tables. 
Instead, you need a `junction` table (also called an associative table or bridging table). 
This table acts as an intermediary to link records from both tables.

```sql
-- Table for Students (Many side)
CREATE TABLE students (
    iid INT PRIMARY KEY,
    name VARCHAR(255)
);

-- Table for Courses (Many side)
CREATE TABLE courses (
    id INT PRIMARY KEY,
    name VARCHAR(255),
    credits INT
);

-- Junction Table: Enrollments (Connects Students and Courses - M-M relationship)
CREATE TABLE enrollments (
    id INT PRIMARY KEY AUTO_INCREMENT, -- Optional, but good practice for junction tables
    student_id INT,
    course_id INT,
    enrollment_date DATE,
    -- Composite Foreign Keys (often part of a composite primary key or unique constraint)
    FOREIGN KEY (student_id) REFERENCES students(id),
    FOREIGN KEY (course_id) REFERENCES courses(id),
    UNIQUE KEY (student_id, course_id) -- Prevent duplicate enrollments for the same student and course
);
```

### Why Foreign Keys?

You might think of foreign key constraints as simply a way to validate data - ensuring 
that when you enter a value in a foreign key column, that value actually exists in the primary key 
column of another table. And you'd be partially right! This value checking is the mechanism foreign keys use.

But it's crucial to understand that this validation is not the end goal, it's the means 
to a much larger purpose. Foreign key constraints are fundamentally about:

<Callout collapsed="1. Explicitly Defining and Enforcing Relationships">

We've discussed relationships like `One-to-Many` between Customers and Orders. 
A foreign key is the SQL language's way of telling the database: 

> Hey database, I want to enforce a 1-M relationship here. Every value in the customer_id column of the
Orders table must correspond to a valid customer_id in the Customers table.

It's not just a suggestion; it's a constraint the database actively enforces. 
The database becomes relationship-aware because of the foreign key.
</Callout>

<Callout collapsed="2. Maintaining Referential Integrity">
- This is the core of "data integrity" in the context of relationships. Referential integrity means 
that relationships between tables remain consistent and valid over time.
- Foreign keys prevent orphaned records. What's an orphaned record? In our Customer-Order example, 
an order that exists in the Orders table but doesn't have a corresponding customer in the Customers 
table would be an orphan. Foreign keys prevent this from happening (or control what happens 
if you try to delete a customer with orders - via CASCADE, SET NULL, etc.).
- Why is preventing orphans important? Orphaned records break the logical structure of your data. 
If you have an order without a customer, you lose crucial context. Queries become unreliable, reports
 become inaccurate, and your application's logic can break down.

**Example**:
```
Without a foreign key, you could accidentally delete a customer from the Customers 
table while their orders still exist in the Orders table. Suddenly, you have orders that point to 
a customer that no longer exists! A foreign key constraint prevents this data inconsistency.
```
</Callout>

<Callout collapsed="3. Facilitating Database Design and Understanding">
- Foreign keys are not just about technical enforcement; they are also a crucial part of database design documentation.
- When you see a foreign key in a database schema, it immediately tells you: 
`Table 'X' is related to Table 'Y' in this way.` It's a clear visual and structural indicator of relationships.
- This makes databases easier to understand, maintain, and evolve over time. New developers can quickly 
grasp how different parts of the database are connected.
</Callout>

In essence, foreign key constraints are not just about checking values; they are about:

1. Defining the rules of your data relationships
2. Actively enforcing those rules at the database level
3. Guaranteeing data integrity and consistency within those relationships
4. Making your database more robust, reliable, and understandable

### Why NOT Foreign Keys?

While highly beneficial, there are some scenarios where you might reconsider or use Foreign Keys with caution. 
These are typically edge cases and often involve trade-offs.

<Callout collapsed="1. Performance Overhead in Very High-Write Environments">
- **Scenario**: Extremely high-volume transactional systems (e.g., real-time logging, very high-frequency trading
platforms, massive IoT data ingestion).
- **Explanation**: Every time you insert or update data in a table with a foreign key, the database system 
needs to perform checks to ensure referential integrity. In extremely high-write scenarios, these 
checks can introduce a small but potentially noticeable performance overhead.
</Callout>

<Callout collapsed="2. Distributed Database Systems and Cross-Node Foreign Keys:">
- **Scenario**: Systems where data is distributed across multiple database nodes or clusters (common in sharded databases, cloud environments, and microservices).
- **Explanation**:  Cross-node foreign keys can introduce significant complexity and performance overhead. Validating referential integrity requires communication between nodes, leading to increased latency. Distributed transactions needed to maintain consistency are also more complex and can be less performant than local transactions. In such architectures, application-level data integrity checks or eventual consistency models might be considered alternatives.
</Callout>

<Callout collapsed="3. Legacy Systems and Data Integration with Non-Relational Data:">
- **Scenario**: Integrating a relational database with older legacy systems or non-relational data stores (e.g., NoSQL, flat files, external APIs).
- **Explanation**:  Legacy systems or non-relational data might not consistently adhere to the referential integrity rules enforced by foreign keys.  Imposing foreign keys in such scenarios can lead to data import issues, data inconsistencies, and might necessitate complex data transformation or application-level integrity management instead. You might need to carefully evaluate the data quality and consistency of the external sources and potentially rely on application logic or ETL processes to ensure data integrity instead of strictly enforcing foreign keys at the database level.
</Callout>

You can also check out some great explanations from the PlanetScale team in their [article](https://planetscale.com/docs/learn/operating-without-foreign-key-constraints#why-does-planetscale-not-recommend-constraints)

### Polymorphic Relations

Polymorphic relationships are a more advanced concept that allows a single relationship to point to 
different types of entities or tables. It's about creating more flexible and adaptable relationships when 
you have different kinds of data that share some commonality.

Imagine you have an `activities` log. An activity could be a `comment` a `like` or a `share`.
Each of these `activity` types has different details. Instead of creating separate tables and 
relationships for each activity type and the things they relate to, you might use a polymorphic approach.

<Callout collapsed="Common Scenarios & Examples">
- **Comments/Reviews**: A "Comment" might be related to different types of content: articles, products, videos, etc. 
Instead of having separate article_id, product_id, video_id columns in a Comments table, you can use a 
polymorphic relationship.
```
+---------------------+
| **Comments**        |
+---------------------+
| PK comment_id       |
| commentable_type    | ------>  [Polymorphic Relationship]
| commentable_id      | -------->
| user_id             |
| comment_text        |
| ...                 |
+---------------------+
          ^
          |
+---------------------+    +---------------------+    +---------------------+
| **Articles**        |    | **Products**        |    | **Videos**          |
+---------------------+    +---------------------+    +---------------------+
| PK article_id       |    | PK product_id       |    | PK video_id         |
| ...                 |    | ...                 |    | ...                 |
+---------------------+    +---------------------+    +---------------------+
```
- **Notifications:** A notification could be related to a user, an order, a system event, etc.
```
+----------------------+
| **Notifications**    |
+----------------------+
| PK notification_id  |
| notifiable_type     | ------>  [Polymorphic Relationship]
| notifiable_id       | -------->
| user_id             |
| message             |
| ...                  |
+----------------------+
           ^
           |
+---------------------+    +---------------------+    +-----------------------+
| **Users**           |    | **Orders**          |    | **System Events**     |
+---------------------+    +---------------------+    +-----------------------+
| PK user_id          |    | PK order_id         |    | PK event_id           |
| ...                 |    | ...                 |    | ...                   |
+---------------------+    +---------------------+    +-----------------------+
```
</Callout>

Polymorphic relationships are more complex and are often handled at the application level or 
using more advanced database features (depending on the specific database system). Standard SQL doesn't 
have direct, built-in support for enforcing polymorphic foreign key constraints in the same way as regular foreign keys.

Source: https://orm.drizzle.team/docs/relations

import Tab from '@mdx/Tab.astro';
import Tabs from '@mdx/Tabs.astro';
import IsSupportedChipGroup from '@mdx/IsSupportedChipGroup.astro';
import Callout from '@mdx/Callout.astro';
import Section from '@mdx/Section.astro';

import CodeTab from '@mdx/CodeTab.astro';
import CodeTabs from '@mdx/CodeTabs.astro';

# Drizzle soft relations
The sole purpose of Drizzle relations is to let you query your relational data in the most simple and consise way:

<CodeTabs items={["Relational queries", "Select with joins"]}>
<Section>
```ts
import * as schema from './schema';
import { drizzle } from 'drizzle-orm/…';

const db = drizzle(client, { schema });

const result = db.query.users.findMany({
  with: {
    posts: true,
  },
});
```
```ts
[{
  id: 10,
  name: "Dan",
  posts: [
    {
      id: 1,
      content: "SQL is awesome",
      authorId: 10,
    },
    {
      id: 2,
      content: "But check relational queries",
      authorId: 10,
    }
  ]
}]
```
</Section>
<Section>
```ts
import { drizzle } from 'drizzle-orm/…';
import { eq } from 'drizzle-orm';
import { posts, users } from './schema';

const db = drizzle(client);

const res = await db.select()
                    .from(users)
                    .leftJoin(posts, eq(posts.authorId, users.id))
                    .orderBy(users.id)
const mappedResult =  
```
</Section>
</CodeTabs>


### One-to-one
Drizzle ORM provides you an API to define `one-to-one` relations between tables with the `relations` operator.

An example of a `one-to-one` relation between users and users, where a user can invite another (this example uses a self reference):

```typescript copy {10-15}
import { pgTable, serial, text, integer, boolean } from 'drizzle-orm/pg-core';
import { relations } from 'drizzle-orm';

export const users = pgTable('users', {
	id: serial('id').primaryKey(),
	name: text('name'),
	invitedBy: integer('invited_by'),
});

export const usersRelations = relations(users, ({ one }) => ({
	invitee: one(users, {
		fields: [users.invitedBy],
		references: [users.id],
	}),
}));
```

Another example would be a user having a profile information stored in separate table. In this case, because the foreign key is stored in the "profile_info" table, the user relation have neither fields or references. This tells Typescript that `user.profileInfo` is nullable:

```typescript copy {9-17}
import { pgTable, serial, text, integer, jsonb } from 'drizzle-orm/pg-core';
import { relations } from 'drizzle-orm';

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

export const usersRelations = relations(users, ({ one }) => ({
	profileInfo: one(profileInfo),
}));

export const profileInfo = pgTable('profile_info', {
	id: serial('id').primaryKey(),
	userId: integer('user_id').references(() => users.id),
	metadata: jsonb('metadata'),
});

export const profileInfoRelations = relations(profileInfo, ({ one }) => ({
	user: one(users, { fields: [profileInfo.userId], references: [users.id] }),
}));

const user = await queryUserWithProfileInfo();
//____^? type { id: number, profileInfo: { ... } | null  }
```

### One-to-many
Drizzle ORM provides you an API to define `one-to-many` relations between tables with `relations` operator. 

Example of `one-to-many` relation between users and posts they've written:

```typescript copy {9-11, 19-24}
import { pgTable, serial, text, integer } from 'drizzle-orm/pg-core';
import { relations } from 'drizzle-orm';

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

export const usersRelations = relations(users, ({ many }) => ({
	posts: many(posts),
}));

export const posts = pgTable('posts', {
	id: serial('id').primaryKey(),
	content: text('content'),
	authorId: integer('author_id'),
});

export const postsRelations = relations(posts, ({ one }) => ({
	author: one(users, {
		fields: [posts.authorId],
		references: [users.id],
	}),
}));
```

Now lets add comments to the posts:
```typescript copy {14,17-22,24-29}
...

export const posts = pgTable('posts', {
	id: serial('id').primaryKey(),
	content: text('content'),
	authorId: integer('author_id'),
});

export const postsRelations = relations(posts, ({ one, many }) => ({
	author: one(users, {
		fields: [posts.authorId],
		references: [users.id],
	}),
	comments: many(comments)
}));

export const comments = pgTable('comments', {
	id: serial('id').primaryKey(),
	text: text('text'),
	authorId: integer('author_id'),
	postId: integer('post_id'),
});

export const commentsRelations = relations(comments, ({ one }) => ({
	post: one(posts, {
		fields: [comments.postId],
		references: [posts.id],
	}),
}));
```


### Many-to-many
Drizzle ORM provides you an API to define `many-to-many` relations between tables through so called `junction` or `join` tables,
they have to be explicitly defined and store associations between related tables.  
  
Example of `many-to-many` relation between users and groups:
```typescript copy {9-11, 18-20, 37-46}
import { relations } from 'drizzle-orm';
import { integer, pgTable, primaryKey, serial, text } from 'drizzle-orm/pg-core';

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

export const usersRelations = relations(users, ({ many }) => ({
  usersToGroups: many(usersToGroups),
}));

export const groups = pgTable('groups', {
  id: serial('id').primaryKey(),
  name: text('name'),
});

export const groupsRelations = relations(groups, ({ many }) => ({
  usersToGroups: many(usersToGroups),
}));

export const usersToGroups = pgTable(
  'users_to_groups',
  {
    userId: integer('user_id')
      .notNull()
      .references(() => users.id),
    groupId: integer('group_id')
      .notNull()
      .references(() => groups.id),
  },
  (t) => [
		primaryKey({ columns: [t.userId, t.groupId] })
	],
);

export const usersToGroupsRelations = relations(usersToGroups, ({ one }) => ({
  group: one(groups, {
    fields: [usersToGroups.groupId],
    references: [groups.id],
  }),
  user: one(users, {
    fields: [usersToGroups.userId],
    references: [users.id],
  }),
}));
```

### Foreign keys

You might've noticed that `relations` look similar to foreign keys — they even have a `references` property. So what's the difference?

While foreign keys serve a similar purpose, defining relations between tables, they work on a different level compared to `relations`.

Foreign keys are a database level constraint, they are checked on every `insert`/`update`/`delete` operation and throw an error if a constraint is violated.
On the other hand, `relations` are a higher level abstraction, they are used to define relations between tables on the application level only.
They do not affect the database schema in any way and do not create foreign keys implicitly.

What this means is `relations` and foreign keys can be used together, but they are not dependent on each other.
You can define `relations` without using foreign keys (and vice versa), which allows them to be used with databases that do not support foreign keys.

The following two examples will work exactly the same in terms of querying the data using Drizzle relational queries.
<CodeTabs items={["schema1.ts", "schema2.ts"]}>
<CodeTab>
```ts {15}
export const users = pgTable('users', {
	id: serial('id').primaryKey(),
	name: text('name'),
});

export const usersRelations = relations(users, ({ one, many }) => ({
	profileInfo: one(users, {
		fields: [profileInfo.userId],
		references: [users.id],
	}),
}));

export const profileInfo = pgTable('profile_info', {
	id: serial('id').primaryKey(),
	userId: integer("user_id"),
	metadata: jsonb("metadata"),
});
```
</CodeTab>
<CodeTab>
```ts {15}
export const users = pgTable('users', {
	id: serial('id').primaryKey(),
	name: text('name'),
});

export const usersRelations = relations(users, ({ one, many }) => ({
	profileInfo: one(users, {
		fields: [profileInfo.userId],
		references: [users.id],
	}),
}));

export const profileInfo = pgTable('profile_info', {
	id: serial('id').primaryKey(),
	userId: integer("user_id").references(() => users.id),
	metadata: jsonb("metadata"),
});
```
</CodeTab>
</CodeTabs>

### Foreign key actions

For more information check the [PostgreSQL foreign keys docs](https://www.postgresql.org/docs/current/ddl-constraints.html#DDL-CONSTRAINTS-FK)

You can specify actions that should occur when the referenced data in the parent table is modified. These actions are known as "foreign key actions." PostgreSQL provides several options for these actions.

On Delete/ Update Actions

- `CASCADE`: When a row in the parent table is deleted, all corresponding rows in the child table will also be deleted. This ensures that no orphaned rows exist in the child table.

- `NO ACTION`: This is the default action. It prevents the deletion of a row in the parent table if there are related rows in the child table. The DELETE operation in the parent table will fail.

- `RESTRICT`: Similar to NO ACTION, it prevents the deletion of a parent row if there are dependent rows in the child table. It is essentially the same as NO ACTION and included for compatibility reasons.

- `SET DEFAULT`: If a row in the parent table is deleted, the foreign key column in the child table will be set to its default value if it has one. If it doesn't have a default value, the DELETE operation will fail.

- `SET NULL`: When a row in the parent table is deleted, the foreign key column in the child table will be set to NULL. This action assumes that the foreign key column in the child table allows NULL values.

> Analogous to ON DELETE there is also ON UPDATE which is invoked when a referenced column is changed (updated). The possible actions are the same, except that column lists cannot be specified for SET NULL and SET DEFAULT. In this case, CASCADE means that the updated values of the referenced column(s) should be copied into the referencing row(s).
in drizzle you can add foreign key action using `references()` second argument.

type of the actions

```typescript
export type UpdateDeleteAction = 'cascade' | 'restrict' | 'no action' | 'set null' | 'set default';

// second argument of references interface
actions?: {
		onUpdate?: UpdateDeleteAction;
		onDelete?: UpdateDeleteAction;
	} | undefined
```

In the following example, adding `onDelete: 'cascade'` to the author field on the `posts` schema means that deleting the `user` will also delete all related Post records.


```typescript {11}
import { pgTable, serial, text, integer } from 'drizzle-orm/pg-core';

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

export const posts = pgTable('posts', {
	id: serial('id').primaryKey(),
	name: text('name'),
	author: integer('author').references(() => users.id, {onDelete: 'cascade'}).notNull(),
});
```

For constraints specified with the `foreignKey` operator, foreign key actions are defined with the syntax:

```typescript {18-19}
import { foreignKey, pgTable, serial, text, integer } from 'drizzle-orm/pg-core';

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

export const posts = pgTable('posts', {
	id: serial('id').primaryKey(),
	name: text('name'),
	author: integer('author').notNull(),
}, (table) => [
	foreignKey({
		name: "author_fk",
		columns: [table.author],
		foreignColumns: [users.id],
	})
		.onDelete('cascade')
		.onUpdate('cascade')
]);
```

### Disambiguating relations

Drizzle also provides the `relationName` option as a way to disambiguate
relations when you define multiple of them between the same two tables. For
example, if you define a `posts` table that has the `author` and `reviewer`
relations.

```ts {9-12, 21-32}
import { pgTable, serial, text, integer } from 'drizzle-orm/pg-core';
import { relations } from 'drizzle-orm';
 
export const users = pgTable('users', {
	id: serial('id').primaryKey(),
	name: text('name'),
});
 
export const usersRelations = relations(users, ({ many }) => ({
	author: many(posts, { relationName: 'author' }),
	reviewer: many(posts, { relationName: 'reviewer' }),
}));
 
export const posts = pgTable('posts', {
	id: serial('id').primaryKey(),
	content: text('content'),
	authorId: integer('author_id'),
	reviewerId: integer('reviewer_id'),
});
 
export const postsRelations = relations(posts, ({ one }) => ({
	author: one(users, {
		fields: [posts.authorId],
		references: [users.id],
		relationName: 'author',
	}),
	reviewer: one(users, {
		fields: [posts.reviewerId],
		references: [users.id],
		relationName: 'reviewer',
	}),
}));
```


Source: https://orm.drizzle.team/docs/seed-functions

import Callout from '@mdx/Callout.astro';
import Tab from "@mdx/Tab.astro";
import Tabs from "@mdx/Tabs.astro";

# Generators

<Callout title='warning'>
For now, specifying `arraySize` along with `isUnique` in generators that support it will result in unique values being generated (not unique arrays), which will then be packed into arrays.
</Callout>

## ---

### `default`

<rem025 />
Generates the same given value each time the generator is called.

|  | param          | default     | type
|:-| :--------      | :--------   | :--------
|  |`defaultValue`  |--           |`any`
|  |`arraySize`     |--           |`number`

<rem025 />

```ts 
import { seed } from "drizzle-seed";

await seed(db, schema, { count: 1000 }).refine((funcs) => ({
  posts: {
    columns: {
      content: funcs.default({
        // value you want to generate
        defaultValue: "post content",

        // number of elements in each one-dimensional array. 
        // (If specified, arrays will be generated.)
        arraySize: 3
      }),
    },
  },
}));

```

### `valuesFromArray`

<rem025 />
Generates values from given array

|  | param      | default                     | type
|:-| :--------  | :--------                   | :--------
|  |`values`    |--                           |`any[]` \| `{ weight: number; values: any[] }[]`
|  |`isUnique`  |`database column uniqueness` |`boolean`
|  |`arraySize` |--                           |`number`


<rem025 />
```ts 
import { seed } from "drizzle-seed";

await seed(db, schema, { count: 1000 }).refine((funcs) => ({
  posts: {
    columns: {
      title: funcs.valuesFromArray({
        // Array of values you want to generate (can be an array of weighted values)
        values: ["Title1", "Title2", "Title3", "Title4", "Title5"],

        // Property that controls whether the generated values will be unique or not
        isUnique: true,
        
        // number of elements in each one-dimensional array. 
        // (If specified, arrays will be generated.)
        arraySize: 3
      }),
    },
  },
}));

```

### `intPrimaryKey`

<rem025 />
Generates sequential integers starting from 1.

|  | param      | default    | type
|:-| :--------  | :--------  | :--------
|  |--          |--          |--

<rem025 />

```ts 
import { seed } from "drizzle-seed";

await seed(db, schema, { count: 1000 }).refine((funcs) => ({
  posts: {
    columns: {
      id: funcs.intPrimaryKey(),
    },
  },
}));

```

### `number`

<rem025 />
Generates numbers with a floating point within the given range

|  | param      | default                                                                                               | type
|:-| :--------  | :--------                                                                                             | :--------
|  |`isUnique`  |`database column uniqueness`                                                                           |`boolean`
|  |`precision` |`100`                                                                                                  |`number`
|  |`maxValue`  |``` `precision * 1000` if isUnique equals false``` ``` `precision * count` if isUnique equals true```  |`number`
|  |`minValue`  |`-maxValue`                                                                                            |`number`
|  |`arraySize` |--                                                                                                     |`number`

<rem025 />
```ts 
import { seed } from "drizzle-seed";

await seed(db, schema, { count: 1000 }).refine((funcs) => ({
  products: {
    columns: {
      unitPrice: funcs.number({
        // lower border of range.
        minValue: 10,

        // upper border of range.
        maxValue: 120,
        
        // precision of generated number:
        // precision equals 10 means that values will be accurate to one tenth (1.2, 34.6);
        // precision equals 100 means that values will be accurate to one hundredth (1.23, 34.67).
        precision: 100,

        // property that controls if generated values gonna be unique or not.
        isUnique: false,

        // number of elements in each one-dimensional array. 
        // (If specified, arrays will be generated.)
        arraySize: 3
      }),
    },
  },
}));

```

### `int`

<rem025 />
Generates integers within the given range

|  | param      | default                                                                            | type
|:-| :--------  | :--------                                                                          | :--------
|  |`isUnique`  |`database column uniqueness`                                                        |`boolean`
|  |`maxValue`  |``` `1000` if isUnique equals false``` ``` `count * 10` if isUnique equals true```  |`number \| bigint`
|  |`minValue`  |`-maxValue`                                                                         |`number \| bigint`
|  |`arraySize` |--                                                                                  |`number`

<rem025 />
```ts 
import { seed } from "drizzle-seed";

await seed(db, schema, { count: 1000 }).refine((funcs) => ({
  products: {
    columns: {
      unitsInStock: funcs.int({
        // lower border of range.
        minValue: 0,

        // lower border of range.
        maxValue: 100,

        // property that controls if generated values gonna be unique or not.
        isUnique: false,

        // number of elements in each one-dimensional array. 
        // (If specified, arrays will be generated.)
        arraySize: 3
      }),
    },
  },
}));

```

### `boolean`

<rem025 />
Generates boolean values (true or false)

|  | param      | default    | type
|:-| :--------  | :--------  | :--------
|  |`arraySize` |--          |`number`

<rem025 />
```ts 
import { seed } from "drizzle-seed";

await seed(db, schema, { count: 1000 }).refine((funcs) => ({
  users: {
    columns: {
      isAvailable: funcs.boolean({
        // number of elements in each one-dimensional array. 
        // (If specified, arrays will be generated.)
        arraySize: 3
      }),
    },
  },
}));

```

### `date`

<rem025 />
Generates a date within the given range

|  | param      | default                                                                                                   | type
|:-| :--------  | :--------------                                                                                           | :--------
|  |`minDate`   |``` `'2024-05-08' - 4 years` - if maxDate is not set``` ``` `maxDate - 8 years`  - if maxDate is set ```   |`string \| Date`
|  |`maxDate`   |``` `'2024-05-08' + 4 years` - if minDate is not set``` ``` `minDate + 8 years`  - if minDate is set ```   |`string \| Date`
|  |`arraySize` |--                                                                                                         |`number`

<Callout type='warning'>
If only one of the parameters (`minDate` or `maxDate`) is provided, the unspecified parameter will be calculated by adding or subtracting 8 years to/from the specified one
</Callout>

<rem025 />
```ts 
import { seed } from "drizzle-seed";

await seed(db, schema, { count: 1000 }).refine((funcs) => ({
  users: {
    columns: {
      birthDate: funcs.date({
        // lower border of range.
        minDate: "1990-01-01",

        // upper border of range.
        maxDate: "2010-12-31",

        // number of elements in each one-dimensional array. 
        // (If specified, arrays will be generated.)
        arraySize: 3
      }),
    },
  },
}));

```

### `time`

<rem025 />
Generates time in 24-hour format

|  | param      | default             | type
|:-| :--------  | :--------           | :--------
|  |`min`       |`'00:00:00.000Z'`    |`string \| Date`
|  |`max`       |`'23:59:59.999Z'`    |`string \| Date`
|  |`arraySize` |--                   |`number`

<rem025 />
```ts 
import { seed } from "drizzle-seed";

await seed(db, schema, { count: 1000 }).refine((funcs) => ({
  users: {
    columns: {
      birthTime: funcs.time({
        // lower border of range.
        min: "11:12:13.141",

        // upper border of range.
        max: "15:16:17.181",

        // number of elements in each one-dimensional array. 
        // (If specified, arrays will be generated.)
        arraySize: 3
      }),
    },
  },
}));

```

### `timestamp`

<rem025 />
Generates timestamps

|  | param           | default                                                                                       | type
|:-| :--------       | :--------                                                                                     | :--------
|  |`min`            |``` `'2024-05-08' - 2 years` - if max is not set``` ``` `max - 4 years` - if max is set ```    |`string \| Date`
|  |`max`            |``` `'2024-05-08' + 2 years` - if min is not set``` ``` `min + 4 years` - if min is set ```    |`string \| Date`
|  |`arraySize`      |--                                                                                             |`number`

<rem025 />
```ts 
import { seed } from "drizzle-seed";

await seed(db, schema, { count: 1000 }).refine((funcs) => ({
  orders: {
    columns: {
      shippedDate: funcs.timestamp({
        // lower border of range.
        min: "2025-03-07T11:12:13.141",

        // upper border of range.
        max: "2025-03-08T15:16:17.181",

        // number of elements in each one-dimensional array. 
        // (If specified, arrays will be generated.)
        arraySize: 3
      }),
    },
  },
}));

```

### `datetime`

<rem025 />
Generates datetime objects

|  | param        | default                                                                                       | type
|:-| :--------    | :--------                                                                                     | :--------
|  |`min`         |``` `'2024-05-08' - 2 years` - if max is not set``` ``` `max - 4 years`  - if max is set ```   |`string \| Date`
|  |`max`         |``` `'2024-05-08' + 2 years` - if min is not set``` ``` `min + 4 years`  - if min is set ```   |`string \| Date`
|  |`arraySize`   |--                                                                                             |`number`
<rem025 />
```ts 
import { seed } from "drizzle-seed";

await seed(db, schema, { count: 1000 }).refine((funcs) => ({
  orders: {
    columns: {
      shippedDate: funcs.datetime({
        // lower border of range.
        min: "2025-03-07 13:12:13Z",
        
        // upper border of range.
        max: "2025-03-09 15:12:13Z",

        // number of elements in each one-dimensional array. 
        // (If specified, arrays will be generated.)
        arraySize: 3
      }),
    },
  },
}));

```

### `year`

<rem025 />
Generates years in `YYYY` format

|  | param      | default    | type
|:-| :--------  | :--------  | :--------
|  |`arraySize` |--          |`number`

<rem025 />
```ts 
import { seed } from "drizzle-seed";

await seed(db, schema, { count: 1000 }).refine((funcs) => ({
  users: {
    columns: {
      birthYear: funcs.year({
        // number of elements in each one-dimensional array. 
        // (If specified, arrays will be generated.)
        arraySize: 3
      }),
    },
  },
}));

```

### `json`

<rem025 />
Generates JSON objects with a fixed structure

```ts
{ email, name, isGraduated, hasJob, salary, startedWorking, visitedCountries}

// or

{ email, name, isGraduated, hasJob, visitedCountries }
```

> The JSON structure will be picked randomly

|  | param      | default    | type
|:-| :--------  | :--------  | :--------
|  |`arraySize` |--          |`number`

<rem025 />
```ts 
import { seed } from "drizzle-seed";

await seed(db, schema, { count: 1000 }).refine((funcs) => ({
  users: {
    columns: {
      metadata: funcs.json({
        // number of elements in each one-dimensional array. 
        // (If specified, arrays will be generated.)
        arraySize: 3
      }),
    },
  },
}));

```

### `interval`

<rem025 />
Generates time intervals.

Example of a generated value: `1 year 12 days 5 minutes`

|  | param      | default                     | type
|:-| :--------  | :--------                   | :--------
|  |`isUnique`  |`database column uniqueness` |`boolean`
|  |`arraySize` |--                           |`number`

<rem025 />
```ts 
import { seed } from "drizzle-seed";

await seed(db, schema, { count: 1000 }).refine((funcs) => ({
  users: {
    columns: {
      timeSpentOnWebsite: funcs.interval({
        // `isUnique` - property that controls whether the generated values will be unique or not
        isUnique: true,

        // number of elements in each one-dimensional array. 
        // (If specified, arrays will be generated.)
        arraySize: 3
      }),
    },
  },
}));

```

### `string`

<rem025 />
Generates random strings

|  | param      | default                     | type
|:-| :--------  | :--------                   | :--------
|  |`isUnique`  |`database column uniqueness` |`boolean`
|  |`arraySize` |--                           |`number`

<rem025 />
```ts 
import { seed } from "drizzle-seed";

await seed(db, schema, { count: 1000 }).refine((funcs) => ({
  users: {
    columns: {
      hashedPassword: funcs.string({
        // `isUnique` - property that controls whether the generated values will be unique or not
        isUnique: false,
        
        // number of elements in each one-dimensional array. 
        // (If specified, arrays will be generated.)
        arraySize: 3
      }),
    },
  },
}));

```

### `uuid`

<rem025 />
Generates v4 UUID strings

|  | param      | default    | type
|:-| :--------  | :--------  | :--------
|  |`arraySize` |--          |`number`

<rem025 />
```ts 
import { seed } from "drizzle-seed";
await seed(db, schema, { count: 1000 }).refine((funcs) => ({
  products: {
    columns: {
      id: funcs.uuid({
        // number of elements in each one-dimensional array. 
        // (If specified, arrays will be generated.)
        arraySize: 3
      }),
    },
  },
}));
```

### `firstName`

<rem025 />
Generates a person's first name

|  | param      | default                     | type
|:-| :--------  | :--------                   | :--------
|  |`isUnique`  |`database column uniqueness` |`boolean`
|  |`arraySize` |--                           |`number`

<rem025 />
```ts 
import { seed } from "drizzle-seed";

await seed(db, schema, { count: 1000 }).refine((funcs) => ({
  users: {
    columns: {
      firstName: funcs.firstName({
        // `isUnique` - property that controls whether the generated values will be unique or not
        isUnique: true,

        // number of elements in each one-dimensional array. 
        // (If specified, arrays will be generated.)
        arraySize: 3
      }),
    },
  },
}));

```

### `lastName`

<rem025 />
Generates a person's last name

|  | param      | default                     | type
|:-| :--------  | :--------                   | :--------
|  |`isUnique`  |`database column uniqueness` |`boolean`
|  |`arraySize` |--                           |`number`

<rem025 />
```ts 
import { seed } from "drizzle-seed";

await seed(db, schema, { count: 1000 }).refine((funcs) => ({
  users: {
    columns: {
      lastName: funcs.lastName({
        // `isUnique` - property that controls whether the generated values will be unique or not
        isUnique: false,
        
        // number of elements in each one-dimensional array. 
        // (If specified, arrays will be generated.)
        arraySize: 3
      }),
    },
  },
}));

```

### `fullName`

<rem025 />
Generates a person's full name

|  | param      | default                     | type
|:-| :--------  | :--------                   | :--------
|  |`isUnique`  |`database column uniqueness` |`boolean`
|  |`arraySize` |--                           |`number`

<rem025 />
```ts 
import { seed } from "drizzle-seed";

await seed(db, schema, { count: 1000 }).refine((funcs) => ({
  users: {
    columns: {
      fullName: funcs.fullName({
        // `isUnique` - property that controls whether the generated values will be unique or not
        isUnique: true,

        // number of elements in each one-dimensional array. 
        // (If specified, arrays will be generated.)
        arraySize: 3
      }),
    },
  },
}));

```

### `email`

<rem025 />
Generates unique email addresses

|  | param      | default    | type
|:-| :--------  | :--------  | :--------
|  |`arraySize` |--          |`number`

<rem025 />
```ts 
import { seed } from "drizzle-seed";

await seed(db, schema, { count: 1000 }).refine((funcs) => ({
  users: {
    columns: {
      email: funcs.email({
        // number of elements in each one-dimensional array. 
        // (If specified, arrays will be generated.)
        arraySize: 3
      }),
    },
  },
}));

```

### `phoneNumber`

<rem025 />
Generates unique phone numbers

|  | param                    | default                                         | type
|:-| :--------                | :--------                                       | :--------
|  |`template`                |--                                               |`string`
|  |`prefixes`                |[Used dataset for prefixes](https://github.com/OleksiiKH0240/drizzle-orm/blob/main/drizzle-seed/src/datasets/phonesInfo.ts)   |`string[]`
|  |`generatedDigitsNumbers`  | `7` - `if prefixes was defined`                 |`number \| number[]`
|  |`arraySize`               |--                                               |`number`

<rem025 />
```ts 
import { seed } from "drizzle-seed";

//generate phone number using template property
await seed(db, schema, { count: 1000 }).refine((funcs) => ({
  users: {
    columns: {
      phoneNumber: funcs.phoneNumber({ 
        // `template` - phone number template, where all '#' symbols will be substituted with generated digits.
        template: "+(380) ###-####",

        // number of elements in each one-dimensional array. 
        // (If specified, arrays will be generated.)
        arraySize: 3
      }),
    },
  },
}));

```
```ts 
import { seed } from "drizzle-seed";

//generate phone number using prefixes and generatedDigitsNumbers properties
await seed(db, schema, { count: 1000 }).refine((funcs) => ({
  users: {
    columns: {
      phoneNumber: funcs.phoneNumber({
        // `prefixes` - array of any string you want to be your phone number prefixes.(not compatible with `template` property)
        prefixes: ["+380 99", "+380 67"],

        // `generatedDigitsNumbers` - number of digits that will be added at the end of prefixes.(not compatible with `template` property)
        generatedDigitsNumbers: 7,

        // number of elements in each one-dimensional array. 
        // (If specified, arrays will be generated.)
        arraySize: 3
      }),
    },
  },
}));

```
```ts 
import { seed } from "drizzle-seed";

// generate phone number using prefixes and generatedDigitsNumbers properties but with different generatedDigitsNumbers for prefixes
await seed(db, schema, { count: 1000 }).refine((funcs) => ({
  users: {
    columns: {
      phoneNumber: funcs.phoneNumber({
        // `prefixes` - array of any string you want to be your phone number prefixes.(not compatible with `template` property)
        prefixes: ["+380 99", "+380 67", "+1"],

        // `generatedDigitsNumbers` - number of digits that will be added at the end of prefixes.(not compatible with `template` property)
        generatedDigitsNumbers: [7, 7, 10],

        // number of elements in each one-dimensional array. 
        // (If specified, arrays will be generated.)
        arraySize: 3
      }),
    },
  },
}));

```
### `country`

<rem025 />
Generates country's names

|  | param      | default                     | type
|:-| :--------  | :--------                   | :--------
|  |`isUnique`  |`database column uniqueness` |`boolean`
|  |`arraySize` |--                           |`number`

<rem025 />

```ts 
import { seed } from "drizzle-seed";

await seed(db, schema, { count: 1000 }).refine((funcs) => ({
  users: {
    columns: {
      country: funcs.country({
        // `isUnique` - property that controls whether the generated values will be unique or not
        isUnique: false,
        
        // number of elements in each one-dimensional array. 
        // (If specified, arrays will be generated.)
        arraySize: 3
      }),
    },
  },
}));

```

### `city`

<rem025 />
Generates city's names

|  | param      | default                     | type
|:-| :--------  | :--------                   | :--------
|  |`isUnique`  |`database column uniqueness` |`boolean`
|  |`arraySize` |--                           |`number`

<rem025 />

```ts 
import { seed } from "drizzle-seed";

await seed(db, schema, { count: 1000 }).refine((funcs) => ({
  users: {
    columns: {
      city: funcs.city({
        // `isUnique` - property that controls whether the generated values will be unique or not
        isUnique: false,

        // number of elements in each one-dimensional array. 
        // (If specified, arrays will be generated.)
        arraySize: 3
      }),
    },
  },
}));

```

### `streetAddress`

<rem025 />
Generates street address

|  | param      | default                     | type
|:-| :--------  | :--------                   | :--------
|  |`isUnique`  |`database column uniqueness` |`boolean`
|  |`arraySize` |--                           |`number`

<rem025 />

```ts 
import { seed } from "drizzle-seed";

await seed(db, schema, { count: 1000 }).refine((funcs) => ({
  users: {
    columns: {
      streetAddress: funcs.streetAddress({
        // `isUnique` - property that controls whether the generated values will be unique or not
        isUnique: false,
        
        // number of elements in each one-dimensional array. 
        // (If specified, arrays will be generated.)
        arraySize: 3 
      }),
    },
  },
}));

```

### `jobTitle`

<rem025 />
Generates job titles

|  | param      | default    | type
|:-| :--------  | :--------  | :--------
|  |`arraySize` |--          |`number`

<rem025 />

```ts 
import { seed } from "drizzle-seed";

await seed(db, schema, { count: 1000 }).refine((funcs) => ({
  users: {
    columns: {
      jobTitle: funcs.jobTitle({
        // number of elements in each one-dimensional array. 
        // (If specified, arrays will be generated.)
        arraySize: 3
      }),
    },
  },
}));

```

### `postcode`

<rem025 />
Generates postal codes

|  | param      | default                     | type
|:-| :--------  | :--------                   | :--------
|  |`isUnique`  |`database column uniqueness` |`boolean`
|  |`arraySize` |--                           |`number`

<rem025 />

```ts 
import { seed } from "drizzle-seed";

await seed(db, schema, { count: 1000 }).refine((funcs) => ({
  users: {
    columns: {
      postcode: funcs.postcode({
        // `isUnique` - property that controls whether the generated values will be unique or not
        isUnique: true,

        // number of elements in each one-dimensional array. 
        // (If specified, arrays will be generated.)
        arraySize: 3
      }),
    },
  },
}));

```

### `state`

<rem025 />
Generates US states

|  | param      | default    | type
|:-| :--------  | :--------  | :--------
|  |`arraySize` |--          |`number`

<rem025 />

```ts 
import { seed } from "drizzle-seed";

await seed(db, schema, { count: 1000 }).refine((funcs) => ({
  users: {
    columns: {
      state: funcs.state({
        // number of elements in each one-dimensional array. 
        // (If specified, arrays will be generated.)
        arraySize: 3
      }),
    },
  },
}));

```

### `companyName`

<rem025 />
Generates random company's names

|  | param      | default                     | type
|:-| :--------  | :--------                   | :--------
|  |`isUnique`  |`database column uniqueness` |`boolean`
|  |`arraySize` |--                           |`number`

<rem025 />

```ts 
import { seed } from "drizzle-seed";

await seed(db, schema, { count: 1000 }).refine((funcs) => ({
  users: {
    columns: {
      company: funcs.companyName({ 
        // `isUnique` - property that controls whether the generated values will be unique or not
        isUnique: true,

        // number of elements in each one-dimensional array. 
        // (If specified, arrays will be generated.)
        arraySize: 3
      }),
    },
  },
}));

```
### `loremIpsum`

<rem025 />
Generates `lorem ipsum` text sentences.

|  | param            | default    | type
|:-| :--------        | :--------  | :--------
|  |`sentencesCount`  | 1          |`number`
|  |`arraySize`       |--          |`number`

<rem025 />

```ts 
import { seed } from "drizzle-seed";

await seed(db, schema, { count: 1000 }).refine((funcs) => ({
  posts: {
    columns: {
      content: funcs.loremIpsum({
        // `sentencesCount` - number of sentences you want to generate as one generated value(string).
        sentencesCount: 2,

        // number of elements in each one-dimensional array. 
        // (If specified, arrays will be generated.)
        arraySize: 3
      }),
    },
  },
}));

```

### `point`

<rem025 />
Generates 2D points within specified ranges for x and y coordinates.

|  | param       | default                                                                                 | type
|:-| :--------   | :--------                                                                               | :--------
|  |`isUnique`   |`database column uniqueness`                                                             |`boolean`
|  |`maxXValue`  |``` `10 * 1000` if isUnique equals false``` ``` `10 * count` if isUnique equals true```  |`number`
|  |`minXValue`  |`-maxXValue`                                                                             |`number`
|  |`maxYValue`  |``` `10 * 1000` if isUnique equals false``` ``` `10 * count` if isUnique equals true```  |`number`
|  |`minYValue`  |`-maxYValue`                                                                             |`number`
|  |`arraySize`  |--                                                                                       |`number`


<rem025 />

```ts 
import { seed } from "drizzle-seed";

await seed(db, schema, { count: 1000 }).refine((funcs) => ({
  triangles: {
    columns: {
      pointCoords: funcs.point({
        // `isUnique` - property that controls if generated values gonna be unique or not.
        isUnique: true,

        // `minXValue` - lower bound of range for x coordinate.
        minXValue: -5,

        // `maxXValue` - upper bound of range for x coordinate.
        maxXValue: 20,

        // `minYValue` - lower bound of range for y coordinate.
        minYValue: 0,

        // `maxYValue` - upper bound of range for y coordinate.
        maxYValue: 30,

        // number of elements in each one-dimensional array. 
        // (If specified, arrays will be generated.)
        arraySize: 3
      }),
    },
  },
}));

```

### `line`

<rem025 />
Generates 2D lines within specified ranges for a, b and c parameters of line.

```
line equation: a*x + b*y + c = 0
```

|  | param       | default                                                                                 | type
|:-| :--------   | :--------                                                                               | :--------
|  |`isUnique`   |`database column uniqueness`                                                             |`boolean`
|  |`maxAValue`  |``` `10 * 1000` if isUnique equals false``` ``` `10 * count` if isUnique equals true```  |`number`
|  |`minAValue`  |`-maxAValue`                                                                             |`number`
|  |`maxBValue`  |``` `10 * 1000` if isUnique equals false``` ``` `10 * count` if isUnique equals true```  |`number`
|  |`minBValue`  |`-maxBValue`                                                                             |`number`
|  |`maxCValue`  |``` `10 * 1000` if isUnique equals false``` ``` `10 * count` if isUnique equals true```  |`number`
|  |`minCValue`  |`-maxCValue`                                                                             |`number`
|  |`arraySize`  |--                                                                                       |`number`
<rem025 />

```ts 
import { seed } from "drizzle-seed";

await seed(db, schema, { count: 1000 }).refine((funcs) => ({
  lines: {
    columns: {
      lineParams: funcs.point({
        // `isUnique` - property that controls if generated values gonna be unique or not.
        isUnique: true,

        // `minAValue` - lower bound of range for a parameter.
        minAValue: -5,

        // `maxAValue` - upper bound of range for x parameter.
        maxAValue: 20,

        // `minBValue` - lower bound of range for y parameter.
        minBValue: 0,

        // `maxBValue` - upper bound of range for y parameter.
        maxBValue: 30,

        // `minCValue` - lower bound of range for y parameter.
        minCValue: 0,

        // `maxCValue` - upper bound of range for y parameter.
        maxCValue: 10,

        // number of elements in each one-dimensional array. 
        // (If specified, arrays will be generated.)
        arraySize: 3
      }),
    },
  },
}));

```

### `bitString`

<rem025 />
Generates bit strings based on specified parameters.

|  | param       | default                                                                                 | type
|:-| :--------   | :--------                                                                               | :--------
|  |`isUnique`   |`database column uniqueness`                                                             |`boolean`
|  |`dimensions` |`database column bit-length`                                                             |`number`
|  |`arraySize`  |--                                                                                       |`number`
<rem025 />

```ts 
import { seed } from "drizzle-seed";

await seed(db, schema, { count: 1000 }).refine((funcs) => ({
  bitStringTable: {
    columns: {
      bit: funcs.bitString({
        // desired length of each bit string (e.g., `dimensions = 3` produces values like `'010'`).
        dimensions: 12,

        // property that controls if generated values gonna be unique or not;
        isUnique: true,

        // number of elements in each one-dimensional array (If specified, arrays will be generated);
        arraySize: 3,
      }),
    },
  },
}));

```

### `inet`

<rem025 />
Generates ip addresses based on specified parameters.

|  | param       | default                                                                                 | type
|:-| :--------   | :--------                                                                               | :--------
|  |`isUnique`   |`database column uniqueness`                                                             |`boolean`
|  |`arraySize`  |--                                                                                       |`number`
|  |`ipAddress`  |`'ipv4'`                                                                                 |`'ipv4' \| 'ipv6'`
|  |`includeCidr`|`true`                                                                                   |`boolean`
<rem025 />

```ts 
import { seed } from "drizzle-seed";

await seed(db, schema, { count: 1000 }).refine((funcs) => ({
  inetTable: {
    columns: {
      inet: funcs.inet({
        // property that controls if generated values gonna be unique or not;
        isUnique: true,

        // number of elements in each one-dimensional array (If specified, arrays will be generated);
        arraySize: 3,

        // type of IP address to generate — either "ipv4" or "ipv6";
        ipAddress: "ipv4",

        // determines whether generated IPs include a CIDR suffix.
        includeCidr: true,
      }),
    },
  },
}));
```

### `geometry`

<rem025 />
Generates geometry objects based on the given parameters.

<Callout title='warnings'>
<Tabs items={['arraySize', 'srid']}>
<Tab>
Currently, if you set arraySize to a value greater than 1 
or try to insert more than one `geometry point` element into a `geometry(point, 0)[]` column in PostgreSQL or CockroachDB via drizzle-orm, 
you’ll encounter an error.

This bug is already in the backlog.

<Callout title="❌">
```ts {13}
import { seed } from "drizzle-seed";
import { geometry, pgTable } from 'drizzle-orm/pg-core';

const geometryTable = pgTable('geometry_table', {
	geometryArray: geometry('geometry_array', { type: 'point', srid: 0 }).array(3),
});

await seed(db, { geometryTable }, { count: 1000 }).refine((funcs) => ({
  geometryTable: {
    columns: {
      geometryArray: funcs.geometry({
        // currently arraySize with values > 1 are not supported
        arraySize: 3,
      }),
    },
  },
}));
```
</Callout>

<Callout title='✅'>
```ts {13}
import { seed } from "drizzle-seed";
import { geometry, pgTable } from 'drizzle-orm/pg-core';

const geometryTable = pgTable('geometry_table', {
	geometryArray: geometry('geometry_array', { type: 'point', srid: 0 }).array(1),
});

await seed(db, { geometryTable }, { count: 1000 }).refine((funcs) => ({
  geometryTable: {
    columns: {
      geometryArray: funcs.geometry({
        // will work as expected
        arraySize: 1,
      }),
    },
  },
}));
```
</Callout>
</Tab>

<Tab>
Currently, if you set the SRID of a `geometry(point)` column to anything other than 0 (for example, 4326) in your drizzle-orm table declaration, 
you’ll encounter an error during the seeding process.

This bug is already in the backlog.

<Callout title="❌">
```ts {5}
import { seed } from "drizzle-seed";
import { geometry, pgTable } from 'drizzle-orm/pg-core';

const geometryTable = pgTable('geometry_table', {
	geometryColumn: geometry('geometry_column', { type: 'point', srid: 4326 }),
});

await seed(db, { geometryTable }, { count: 1000 }).refine((funcs) => ({
  geometryTable: {
    columns: {
      geometryColumn: funcs.geometry({
        srid: 4326,
      }),
    },
  },
}));
```
</Callout>

<Callout title='✅'>
```ts {5}
import { seed } from "drizzle-seed";
import { geometry, pgTable } from 'drizzle-orm/pg-core';

const geometryTable = pgTable('geometry_table', {
	geometryColumn: geometry('geometry_column', { type: 'point', srid: 0 }),
});

await seed(db, { geometryTable }, { count: 1000 }).refine((funcs) => ({
  geometryTable: {
    columns: {
      geometryColumn: funcs.geometry({
        srid: 4326,
      }),
    },
  },
}));
```
</Callout>
</Tab>
</Tabs>
</Callout>

|  | param          | default                                                                                 | type
|:-| :--------      | :--------                                                                               | :--------
|  |`isUnique`      |`database column uniqueness`                                                             |`boolean`
|  |`arraySize`     |--                                                                                       |`number`
|  |`type`          |`'point'`                                                                                |`'point'`
|  |`srid`          |`4326`                                                                                   |`4326 \| 3857`
|  |`decimalPlaces` |`6`                                                                                      |`1 \| 2 \| 3 \| 4 \| 5 \| 6 \| 7`
<rem025 />

```ts 
import { seed } from "drizzle-seed";

await seed(db, schema, { count: 1000 }).refine((funcs) => ({
  geometryTable: {
    columns: {
      geometryPointTuple: funcs.geometry({
        // property that controls if generated values gonna be unique or not;
        isUnique: true,

        // number of elements in each one-dimensional array (If specified, arrays will be generated);
        arraySize: 1,

        // geometry type to generate; currently only `'point'` is supported;
        type: "point",

        // Spatial Reference System Identifier: determines what type of point will be generated - either `4326` or `3857`;
        srid: 4326,

        // number of decimal places for points when `srid` is `4326` (e.g., `decimalPlaces = 3` produces values like `'point(30.723 46.482)'`).
        decimalPlaces: 5,
      }),
    },
  },
}));

```

### `vector`

<rem025 />
Generates vectors based on the provided parameters.

|  | param          | default                                                      | type
|:-| :--------      | :--------                                                    | :--------
|  |`isUnique`      |`database column uniqueness`                                  |`boolean`
|  |`arraySize`     |--                                                            |`number`
|  |`decimalPlaces` |`2`                                                           |`number`
|  |`dimensions`    |`database column’s dimensions`                                |`number`
|  |`minValue`      |`-1000`                                                       |`number`
|  |`maxValue`      |`1000`                                                        |`number`
<rem025 />

```ts 
import { seed } from "drizzle-seed";

await seed(db, schema, { count: 1000 }).refine((funcs) => ({
  vectorTable: {
    columns: {
      vector: funcs.vector({
        // property that controls if generated values gonna be unique or not;
        isUnique: true,

        // number of elements in each one-dimensional array (If specified, arrays will be generated);
        arraySize: 3,

        // number of decimal places for each vector element (e.g., `decimalPlaces = 3` produces values like `1.123`);
        decimalPlaces: 5,

        // number of elements in each generated vector (e.g., `dimensions = 3` produces values like `[1,2,3]`);
        dimensions: 12,

        // minimum allowed value for each vector element;
        minValue: -100,

        // maximum allowed value for each vector element.
        maxValue: 100,
      }),
    },
  },
}));

```

Source: https://orm.drizzle.team/docs/seed-limitations

// type limitations for third param

Source: https://orm.drizzle.team/docs/singlestore/arktype

import Npm from '@mdx/Npm.astro';
import Callout from '@mdx/Callout.astro';

<Callout type="error">
Starting from `drizzle-orm@1.0.0-beta.15`, `drizzle-arktype` has been deprecated in favor of first-class schema generation support within Drizzle ORM itself

You can still use `drizzle-arktype` package but all new update will be added to Drizzle ORM directly
</Callout>

# arktype

### Install the dependencies

<Npm>
arktype
</Npm>

### Select schema

Defines the shape of data queried from the database - can be used to validate API responses.

```ts copy
import { int, singlestoreTable, text } from 'drizzle-orm/singlestore-core';
import { createSelectSchema } from 'drizzle-orm/arktype';

const users = singlestoreTable('users', {
  id: int().primaryKey().autoincrement(),
  name: text().notNull(),
  age: int().notNull()
});

const userSelectSchema = createSelectSchema(users);

const rows = await db.select({ id: users.id, name: users.name }).from(users).limit(1);
const parsed: { id: number; name: string; age: number } = userSelectSchema(rows[0]); // Error: `age` is not returned in the above query

const rows = await db.select().from(users).limit(1);
const parsed: { id: number; name: string; age: number } = userSelectSchema(rows[0]); // Will parse successfully
```

Column enums are supported through the SingleStore table schema and can be validated with the generated table schemas.

### Insert schema

Defines the shape of data to be inserted into the database - can be used to validate API requests.

```ts copy
import { int, singlestoreTable, text } from 'drizzle-orm/singlestore-core';
import { createInsertSchema } from 'drizzle-orm/arktype';

const users = singlestoreTable('users', {
  id: int().primaryKey().autoincrement(),
  name: text().notNull(),
  age: int().notNull()
});

const userInsertSchema = createInsertSchema(users);

const user = { name: 'John' };
const parsed: { name: string, age: number } = userInsertSchema(user); // Error: `age` is not defined

const user = { name: 'Jane', age: 30 };
const parsed: { name: string, age: number } = userInsertSchema(user); // Will parse successfully
await db.insert(users).values(parsed);
```

### Update schema

Defines the shape of data to be updated in the database - can be used to validate API requests.

```ts copy
import { int, singlestoreTable, text } from 'drizzle-orm/singlestore-core';
import { createUpdateSchema } from 'drizzle-orm/arktype';
import { parse } from 'arktype';

const users = singlestoreTable('users', {
  id: int().primaryKey().autoincrement(),
  name: text().notNull(),
  age: int().notNull()
});

const userUpdateSchema = createUpdateSchema(users);

const user = { id: 5, name: 'John' };
const parsed: { name?: string | undefined, age?: number | undefined } = userUpdateSchema(user); // Error: `id` is a generated column, it can't be updated

const user = { age: 35 };
const parsed: { name?: string | undefined, age?: number | undefined } = userUpdateSchema(user); // Will parse successfully
await db.update(users).set(parsed).where(eq(users.name, 'Jane'));
```

### Refinements

Each create schema function accepts an additional optional parameter that you can used to extend, modify or completely overwite a field's schema. Defining a callback function will extend or modify while providing a arktype schema will overwrite it.

```ts copy
import { int, json, singlestoreTable, text } from 'drizzle-orm/singlestore-core';
import { createSelectSchema } from 'drizzle-orm/arktype';
import { parse, pipe, maxLength, object, string } from 'arktype';

const users = singlestoreTable('users', {
  id: int().primaryKey().autoincrement(),
  name: text().notNull(),
  bio: text(),
  preferences: json()
});

const userSelectSchema = createSelectSchema(users, {
  name: (schema) => pipe(schema, maxLength(20)), // Extends schema
  bio: (schema) => pipe(schema, maxLength(1000)), // Extends schema before becoming nullable/optional
  preferences: object({ theme: string() }) // Overwrites the field, including its nullability
});

const parsed: {
  id: number;
  name: string,
  bio?: string | undefined;
  preferences: {
    theme: string;
  };
} = userSelectSchema(...);
```

### Data type reference

```ts
singlestore.boolean();

// Schema
type.boolean;
```

```ts
singlestore.date({ mode: 'date' });
singlestore.datetime({ mode: 'date' });
singlestore.timestamp({ mode: 'date' });

// Schema
type.Date;
```

```ts
singlestore.binary();
singlestore.date({ mode: 'string' });
singlestore.datetime({ mode: 'string' });
singlestore.decimal();
singlestore.time();
singlestore.timestamp({ mode: 'string' });
singlestore.varbinary();

// Schema
type.string;
```

```ts
singlestore.char({ length: ... });

// Schema
type.string.exactlyLength(length);
```

```ts
singlestore.varchar({ length: ... });

// Schema
type.string.atMostLength(length);
```

```ts
singlestore.text();

// Schema
type.string.atMostLength(65_535); // unsigned 16-bit integer limit
```

```ts
singlestore.text({ enum: ... });
singlestore.char({ enum: ... });
singlestore.varchar({ enum: ... });
singlestore.singlestoreEnum(..., ...);

// Schema
type.enumerated(...enum);
```

```ts
singlestore.tinyint();

// Schema
type.keywords.number.integer.atLeast(-128).atMost(127); // 8-bit integer lower and upper limit
```

```ts
singlestore.tinyint({ unsigned: true });

// Schema
type.keywords.number.integer.atLeast(0).atMost(255); // unsigned 8-bit integer lower and upper limit
```

```ts
singlestore.smallint();

// Schema
type.keywords.number.integer.atLeast(-32_768).atMost(32_767); // 16-bit integer lower and upper limit
```

```ts
singlestore.smallint({ unsigned: true });

// Schema
type.keywords.number.integer.atLeast(0).atMost(65_535); // unsigned 16-bit integer lower and upper limit
```

```ts
singlestore.float();

// Schema
type.number.atLeast(-8_388_608).atMost(8_388_607); // 24-bit integer lower and upper limit
```

```ts
singlestore.mediumint();

// Schema
type.keywords.number.integer.atLeast(-8_388_608).atMost(8_388_607); // 24-bit integer lower and upper limit
```

```ts
singlestore.float({ unsigned: true });

// Schema
type.number.atLeast(0).atMost(16_777_215); // unsigned 24-bit integer lower and upper limit
```

```ts
singlestore.mediumint({ unsigned: true });

// Schema
type.keywords.number.integer.atLeast(0).atMost(16_777_215); // unsigned 24-bit integer lower and upper limit
```

```ts
singlestore.int();

// Schema
type.keywords.number.integer.atLeast(-2_147_483_648).atMost(2_147_483_647); // 32-bit integer lower and upper limit
```

```ts
singlestore.int({ unsigned: true });

// Schema
type.keywords.number.integer.atLeast(0).atMost(4_294_967_295); // unsgined 32-bit integer lower and upper limit
```

```ts
singlestore.double();
singlestore.real();

// Schema
type.number.atLeast(-140_737_488_355_328).atMost(140_737_488_355_327); // 48-bit integer lower and upper limit
```

```ts
singlestore.double({ unsigned: true });

// Schema
type.number.atLeast(0).atMost(281_474_976_710_655); // unsigned 48-bit integer lower and upper limit
```

```ts
singlestore.bigint({ mode: 'number' });

// Schema
type.keywords.number.integer.atLeast(-9_007_199_254_740_991).atMost(9_007_199_254_740_991); // Javascript min. and max. safe integers
```

```ts
singlestore.serial();

// Schema
type.keywords.number.integer.atLeast(0).atMost(9_007_199_254_740_991); // Javascript max. safe integer
```

```ts
singlestore.bigint({ mode: 'bigint' });

// Schema
type.bigint.narrow(
  (value, ctx) => value < -9_223_372_036_854_775_808n ? ctx.mustBe('greater than') : value > 9_223_372_036_854_775_807n ? ctx.mustBe('less than') : true
); // 64-bit integer lower and upper limit
```

```ts
singlestore.bigint({ mode: 'bigint', unsigned: true });

// Schema
type.bigint.narrow(
  (value, ctx) => value < 0n ? ctx.mustBe('greater than') : value > 18_446_744_073_709_551_615n ? ctx.mustBe('less than') : true
); // unsigned 64-bit integer lower and upper limit
```

```ts
singlestore.year();

// Schema
type.keywords.number.integer.atLeast(1_901).atMost(2_155);
```

```ts
singlestore.json();

// Schema
type('string | number | boolean | null').or(type('unknown.any[] | Record<string, unknown.any>'));
```



Source: https://orm.drizzle.team/docs/singlestore/cache

import Callout from '@mdx/Callout.astro';
import Npm from '@mdx/Npm.astro';

# Cache

Drizzle sends every query straight to your database by default. There are no hidden actions, no automatic caching 
or invalidation - you'll always see exactly what runs. If you want caching, you must opt in.

By default, Drizzle uses a `explicit` caching strategy (i.e. `global: false`), so nothing is ever cached unless you ask. 
This prevents surprises or hidden performance traps in your application. 
Alternatively, you can flip on `all` caching (`global: true`) so that every select will look in cache first.

## Quickstart

### Upstash integration

Drizzle provides an `upstashCache()` helper out of the box. By default, this uses Upstash Redis with automatic configuration if environment variables are set.

```ts
import { upstashCache } from "drizzle-orm/cache/upstash";
import { drizzle } from "drizzle-orm/...";

const db = drizzle(process.env.DB_URL!, {
  cache: upstashCache({ token: process.env.UPSTASH_TOKEN, url: process.env.UPSTASH_URL }),
});
```

You can also explicitly define your Upstash credentials, enable global caching for all queries by default or pass custom caching options:

```ts
import { upstashCache } from "drizzle-orm/cache/upstash";
import { drizzle } from "drizzle-orm/...";

const db = drizzle(process.env.DB_URL!, {
  cache: upstashCache({
    // 👇 Redis credentials (optional — can also be pulled from env vars)
    url: '<UPSTASH_URL>',
    token: '<UPSTASH_TOKEN>',

    // 👇 Enable caching for all queries by default (optional)
    global: true,

    // 👇 Default cache behavior (optional)
    config: { ex: 60 }
  })
});
```

## Cache config reference

Drizzle supports the following cache config options for Upstash:

```ts
export type CacheConfig = {
  /**
   * Expiration in seconds (positive integer)
   */
  ex?: number;
  /**
   * Set an expiration (TTL or time to live) on one or more fields of a given hash key.
   * Used for HEXPIRE command
   */
  hexOptions?: "NX" | "nx" | "XX" | "xx" | "GT" | "gt" | "LT" | "lt";
};
```

## Cache usage examples

Once you've configured caching, here's how the cache behaves:

**Case 1: Drizzle with `global: false` (default, opt-in caching)**

```ts
import { upstashCache } from "drizzle-orm/cache/upstash";
import { drizzle } from "drizzle-orm/...";

const db = drizzle(process.env.DB_URL!, {
  // 👇 `global: true` is not passed, false by default
  cache: upstashCache({ url: "", token: "" }),
});
```

In this case, the following query won't read from cache

```ts
const res = await db.select().from(users);

// Any mutate operation will still trigger the cache's onMutate handler
// and attempt to invalidate any cached queries that involved the affected tables
await db.insert(users).value({ email: "cacheman@upstash.com" });
```

To make this query read from the cache, call `.$withCache()`

```ts
const res = await db.select().from(users).$withCache();
```

`.$withCache` has a set of options you can use to manage and configure this specific query strategy

```ts
// rewrite the config for this specific query
.$withCache({ config: {} })

// give this query a custom cache key (instead of hashing query+params under the hood)
.$withCache({ tag: 'custom_key' })

// turn off auto-invalidation for this query
// note: this leads to eventual consistency (explained below)
.$withCache({ autoInvalidate: false })
```

<Callout>
**Eventual consistency example**

This example is only relevant if you manually set `autoInvalidate: false`. By default, `autoInvalidate` is enabled. 

You might want to turn off `autoInvalidate` if:
- your data doesn't change often, and slight staleness is acceptable (e.g. product listings, blog posts)
- you handle cache invalidation manually

In those cases, turning it off can reduce unnecessary cache invalidation. However, in most cases, we recommend keeping the default enabled.

Example: Imagine you cache the following query on `usersTable` with a 3-second TTL:

``` ts
const recent = await db
  .select().from(usersTable)
  .$withCache({ config: { ex: 3 }, autoInvalidate: false });
```

If someone runs `db.insert(usersTable)...` the cache won't be invalidated immediately. For up to 3 seconds, you'll keep seeing the old data until it eventually becomes consistent.
</Callout>

**Case 2: Drizzle with `global: true` option**

```ts
import { upstashCache } from "drizzle-orm/cache/upstash";
import { drizzle } from "drizzle-orm/...";

const db = drizzle(process.env.DB_URL!, {
  cache: upstashCache({ url: "", token: "", global: true }),
});
```

In this case, the following query will read from cache

```ts
const res = await db.select().from(users);
```

If you want to disable cache for this specific query, call `.$withCache(false)`

```ts
// disable cache for this query
const res = await db.select().from(users).$withCache(false);
```

You can also use cache instance from a `db` to invalidate specific tables or tags

```ts
// Invalidate all queries that use the `users` table. You can do this with the Drizzle instance.
await db.$cache.invalidate({ tables: users });
// or
await db.$cache.invalidate({ tables: [users, posts] });

// Invalidate all queries that use the `usersTable`. You can do this by using just the table name.
await db.$cache.invalidate({ tables: "usersTable" });
// or
await db.$cache.invalidate({ tables: ["usersTable", "postsTable"] });

// You can also invalidate custom tags defined in any previously executed select queries.
await db.$cache.invalidate({ tags: "custom_key" });
// or
await db.$cache.invalidate({ tags: ["custom_key", "custom_key1"] });
```

## Custom cache

This example shows how to plug in a custom `cache` in Drizzle: you provide functions to fetch data from the cache, store results back into cache, and invalidate entries whenever a mutation runs.

Cache extension provides this set of config options
```ts
export type CacheConfig = {
  /** expire time, in seconds */
  ex?: number;
  /** expire time, in milliseconds */
  px?: number;
  /** Unix time (sec) at which the key will expire */
  exat?: number;
  /** Unix time (ms) at which the key will expire */
  pxat?: number;
  /** retain existing TTL when updating a key */
  keepTtl?: boolean;
  /** options for HEXPIRE (hash-field TTL) */
  hexOptions?: 'NX' | 'XX' | 'GT' | 'LT' | 'nx' | 'xx' | 'gt' | 'lt';
};
```

```ts
const db = drizzle(process.env.DB_URL!, { cache: new TestGlobalCache() });
```

```ts
import Keyv from "keyv";

export class TestGlobalCache extends Cache {
  private globalTtl: number = 1000;
  // This object will be used to store which query keys were used
  // for a specific table, so we can later use it for invalidation.
  private usedTablesPerKey: Record<string, string[]> = {};

  constructor(private kv: Keyv = new Keyv()) {
    super();
  }

  // For the strategy, we have two options:
  // - 'explicit': The cache is used only when .$withCache() is added to a query.
  // - 'all': All queries are cached globally.
  // The default behavior is 'explicit'.
  override strategy(): "explicit" | "all" {
    return "all";
  }

  // This function accepts query and parameters that cached into key param,
  // allowing you to retrieve response values for this query from the cache.
  override async get(key: string): Promise<any[] | undefined> {
    const res = (await this.kv.get(key)) ?? undefined;
    return res;
  }

  // This function accepts several options to define how cached data will be stored:
  // - 'key': A hashed query and parameters.
  // - 'response': An array of values returned by Drizzle from the database.
  // - 'tables': An array of tables involved in the select queries. This information is needed for cache invalidation.
  // - 'isTag': A boolean flag indicating whether this cache entry represents a tag-based query.
  //    When true, the entry is associated with a specific tag rather than table-level invalidation,
  //    allowing you to invalidate cached queries by tag name. See the UpstashCache:
  //    https://github.com/drizzle-team/drizzle-orm/blob/beta/drizzle-orm/src/cache/upstash/cache.ts for an example
  //
  // For example, if a query uses the "users" and "posts" tables, you can store this information. Later, when the app executes
  // any mutation statements on these tables, you can remove the corresponding key from the cache.
  // If you're okay with eventual consistency for your queries, you can skip this option.
  override async put(
    key: string,
    response: any,
    tables: string[],
    isTag: boolean = false,
    config?: CacheConfig,
  ): Promise<void> {
    const ttl = config?.px ?? (config?.ex ? config.ex * 1000 : this.globalTtl);

    await this.kv.set(key, response, ttl);

    for (const table of tables) {
      const keys = this.usedTablesPerKey[table];
      if (keys === undefined) {
        this.usedTablesPerKey[table] = [key];
      } else {
        keys.push(key);
      }
    }
  }

  // This function is called when insert, update, or delete statements are executed.
  // You can either skip this step or invalidate queries that used the affected tables.
  //
  // The function receives an object with two keys:
  // - 'tags': Used for queries labeled with a specific tag, allowing you to invalidate by that tag.
  // - 'tables': The actual tables affected by the insert, update, or delete statements,
  //   helping you track which tables have changed since the last cache update.
  override async onMutate(params: {
    tags: string | string[];
    tables: string | string[] | Table<any> | Table<any>[];
  }): Promise<void> {
    const tagsArray = params.tags
      ? Array.isArray(params.tags)
        ? params.tags
        : [params.tags]
      : [];
    const tablesArray = params.tables
      ? Array.isArray(params.tables)
        ? params.tables
        : [params.tables]
      : [];

    const keysToDelete = new Set<string>();

    for (const table of tablesArray) {
      const tableName = is(table, Table)
        ? getTableName(table)
        : (table as string);
      const keys = this.usedTablesPerKey[tableName] ?? [];
      for (const key of keys) keysToDelete.add(key);
    }

    if (keysToDelete.size > 0 || tagsArray.length > 0) {
      for (const tag of tagsArray) {
        await this.kv.delete(tag);
      }

      for (const key of keysToDelete) {
        await this.kv.delete(key);
        for (const table of tablesArray) {
          const tableName = is(table, Table)
            ? getTableName(table)
            : (table as string);
          this.usedTablesPerKey[tableName] = [];
        }
      }
    }
  }
}
```

## Limitations

#### Queries that won't be handled by the `cache` extension:

- Using cache with raw queries, such as:

```ts
db.execute(sql`select 1`);
```

- Using cache with `batch` feature in `d1` and `libsql`

```ts
db.batch([
    db.insert(users).values(...),
    db.update(users).set(...).where()
])
```

- Using cache in transactions
```ts
await db.transaction(async (tx) => {
  await tx.update(accounts).set(...).where(...);
  await tx.update...
});
```

#### Limitations that are temporary and will be handled soon:

- Using cache with Drizzle Relational Queries
```ts
await db.query.users.findMany();
```

- Using cache with views


Source: https://orm.drizzle.team/docs/singlestore/column-types

import Section from '@mdx/Section.astro';
import Callout from '@mdx/Callout.astro';

We have native support for all of them, yet if that's not enough for you, feel free to create **[custom types](/docs/singlestore/custom-types)**.

<Callout title='important' type='warning'>
All examples in this part of the documentation do not use database column name aliases, and column names are generated from TypeScript keys. 

You can use database aliases in column names if you want, and you can also use the `casing` parameter to define a mapping strategy for Drizzle. 

You can read more about it [here](/docs/singlestore/sql-schema-declaration#shape-your-data-schema)
</Callout>

### integer

A signed integer, stored in `0`, `1`, `2`, `3`, `4`, `6`, or `8` bytes depending on the magnitude of the value.

<Section>
```typescript
import { int, singlestoreTable } from "drizzle-orm/singlestore-core";

const table = singlestoreTable('table', {
	int: int()
});
```

```sql
CREATE TABLE `table` (
	`int` int
);
```
</Section>

### tinyint

<Section>
```typescript
import { tinyint, singlestoreTable } from "drizzle-orm/singlestore-core";

const table = singlestoreTable('table', {
	tinyint: tinyint()
});
```

```sql
CREATE TABLE `table` (
	`tinyint` tinyint
);
```
</Section>

### smallint

<Section>
```typescript
import { smallint, singlestoreTable } from "drizzle-orm/singlestore-core";

const table = singlestoreTable('table', {
	smallint: smallint()
});
```

```sql
CREATE TABLE `table` (
	`smallint` smallint
);
```
</Section>

### mediumint

<Section>
```typescript
import { mediumint, singlestoreTable } from "drizzle-orm/singlestore-core";

const table = singlestoreTable('table', {
	mediumint: mediumint()
});
```

```sql
CREATE TABLE `table` (
	`mediumint` mediumint
);
```
</Section>

### bigint

<Section>
```typescript
import { bigint, singlestoreTable } from "drizzle-orm/singlestore-core";

const table = singlestoreTable('table', {
	bigint: bigint({ mode: 'number' })
	bigintUnsigned: bigint({ mode: 'number', unsigned: true })
});

bigint('...', { mode: 'number' | 'bigint' });

// You can also specify unsigned option for bigint
bigint('...', { mode: 'number' | 'bigint', unsigned: true })
```

```sql
CREATE TABLE `table` (
	`bigint` bigint,
	`bigintUnsigned` bigint unsigned
);
```
</Section>

We've omitted config of `M` in `bigint(M)`, since it indicates the display width of the numeric type 

## ---

### real

<Section>
```typescript
import { real, singlestoreTable } from "drizzle-orm/singlestore-core";

const table = singlestoreTable('table', {
	real: real()
});
```

```sql
CREATE TABLE `table` (
	`real` real
);
```
</Section>

<Section>
```typescript
import { real, singlestoreTable } from "drizzle-orm/singlestore-core";

const table = singlestoreTable('table', {
	realPrecision: real({ precision: 1,}),
	realPrecisionScale: real({ precision: 1, scale: 1,}),
});
```

```sql
CREATE TABLE `table` (
	`realPrecision` real(1),
	`realPrecisionScale` real(1, 1)
);
```
</Section>

### decimal

<Section>
```typescript
import { decimal, singlestoreTable } from "drizzle-orm/singlestore-core";

const table = singlestoreTable('table', {
	decimal: decimal(),
	decimalNum: decimal({ scale: 30, mode: 'number' }),
	decimalBig: decimal({ scale: 30, mode: 'bigint' }),
});
```

```sql
CREATE TABLE `table` (
	`decimal` decimal,
	`decimalNum` decimal(30),
	`decimalBig` decimal(30)
);
```
</Section>

<Section>
```typescript
import { decimal, singlestoreTable } from "drizzle-orm/singlestore-core";

const table = singlestoreTable('table', {
	decimalPrecision: decimal({ precision: 1,}),
	decimalPrecisionScale: decimal({ precision: 1, scale: 1,}),
});
```

```sql
CREATE TABLE `table` (
	`decimalPrecision` decimal(1),
	`decimalPrecisionScale` decimal(1, 1)
);
```
</Section>

### double

<Section>
```typescript
import { double, singlestoreTable } from "drizzle-orm/singlestore-core";

const table = singlestoreTable('table', {
	double: double('double')
});
```

```sql
CREATE TABLE `table` (
	`double` double
);
```
</Section>

<Section>
```typescript
import { double, singlestoreTable } from "drizzle-orm/singlestore-core";

const table = singlestoreTable('table', {
	doublePrecision: double({ precision: 1,}),
	doublePrecisionScale: double({ precision: 1, scale: 1,}),
});
```

```sql
CREATE TABLE `table` (
	`doublePrecision` double(1),
	`doublePrecisionScale` double(1, 1)
);
```
</Section>

### float

<Section>
```typescript
import { float, singlestoreTable } from "drizzle-orm/singlestore-core";

const table = singlestoreTable('table', {
	float: float()
});
```

```sql
CREATE TABLE `table` (
	`float` float
);
```
</Section>

## ---

### serial

<Section>

`SERIAL` is an alias for `BIGINT UNSIGNED NOT NULL AUTO_INCREMENT UNIQUE`.

```typescript
import { serial, singlestoreTable } from "drizzle-orm/singlestore-core";

const table = singlestoreTable('table', {
	serial: serial()
});
```

```sql
CREATE TABLE `table` (
	`serial` serial AUTO_INCREMENT
);
```
</Section>

## ---

### binary

<Section>
```typescript
import { binary, singlestoreTable } from "drizzle-orm/singlestore-core";

const table = singlestoreTable('table', {
	binary: binary()
});
```

```sql
CREATE TABLE `table` (
	`binary` binary
);
```
</Section>

### varbinary

<Section>
```typescript
import { varbinary, singlestoreTable } from "drizzle-orm/singlestore-core";

const table = singlestoreTable('table', {
	varbinary: varbinary({ length: 2}),
});
```

```sql
CREATE TABLE `table` (
	`varbinary` varbinary(2)
);
```
</Section>

## ---

### char

<Section>
```typescript
import { char, singlestoreTable } from "drizzle-orm/singlestore-core";

const table = singlestoreTable('table', {
	char: char(),
});
```

```sql
CREATE TABLE `table` (
	`char` char
);
```
</Section>

### varchar
You can define `{ enum: ["value1", "value2"] }` config to infer `insert` and `select` types, it **won't** check runtime values.
<Section>
```typescript
import { varchar, singlestoreTable } from "drizzle-orm/singlestore-core";

const table = singlestoreTable('table', {
	varchar: varchar({ length: 2 }),
});

// will be inferred as text: "value1" | "value2" | null
varchar: varchar({ length: 6, enum: ["value1", "value2"] })
```

```sql
CREATE TABLE `table` (
	`varchar` varchar(2)
);
```
</Section>

### text

You can define `{ enum: ["value1", "value2"] }` config to infer `insert` and `select` types, it **won't** check runtime values.

<Section>
```typescript
import { text, singlestoreTable } from "drizzle-orm/singlestore-core";

const table = singlestoreTable('table', {
	text: text(),
});

// will be inferred as text: "value1" | "value2" | null
text: text({ enum: ["value1", "value2"] });
```

```sql
CREATE TABLE `table` (
	`text` text
);
```
</Section>

## ---

### boolean

<Section>
```typescript
import { boolean, singlestoreTable } from "drizzle-orm/singlestore-core";

const table = singlestoreTable('table', {
	boolean: boolean(),
});
```

```sql
CREATE TABLE `table` (
	`boolean` boolean
);
```
</Section>

## ---

### date

<Section>
```typescript
import { boolean, singlestoreTable } from "drizzle-orm/singlestore-core";

const table = singlestoreTable('table', {
	date: date(),
});
```

```sql
CREATE TABLE `table` (
	`date` date
);
```
</Section>

### datetime

<Section>
```typescript
import { datetime, singlestoreTable } from "drizzle-orm/singlestore-core";

const table = singlestoreTable('table', {
	datetime: datetime(),
});

datetime('...', { mode: 'date' | "string"}),
```

```sql
CREATE TABLE `table` (
	`datetime` datetime
);
```
</Section>

### time 

<Section>
```typescript
import { time, singlestoreTable } from "drizzle-orm/singlestore-core";

const table = singlestoreTable('table', {
	time: time(),
});
```

```sql
CREATE TABLE `table` (
	`time` time
);
```
</Section>

### year

<Section>
```typescript
import { year, singlestoreTable } from "drizzle-orm/singlestore-core";

const table = singlestoreTable('table', {
	year: year(),
});
```

```sql
CREATE TABLE `table` (
	`year` year
);
```
</Section>

### timestamp

<Section>
```typescript
import { timestamp, singlestoreTable } from "drizzle-orm/singlestore-core";

const table = singlestoreTable('table', {
	timestamp: timestamp(),
});

timestamp('...', { mode: 'date' | "string"}),
```

```sql
CREATE TABLE `table` (
	`timestamp` timestamp
);
```
</Section>

<Section>
```typescript
import { timestamp, singlestoreTable } from "drizzle-orm/singlestore-core";

const table = singlestoreTable('table', {
	timestamp: timestamp().defaultNow(),
});
```

```sql
CREATE TABLE `table` (
	`timestamp` timestamp DEFAULT (now())
);
```
</Section>

## ---

### json

<Section>
```typescript
import { json, singlestoreTable } from "drizzle-orm/singlestore-core";

const table = singlestoreTable('table', {
	json: json(),
});

```

```sql
CREATE TABLE `table` (
	`json` json
);
```
</Section>

You can specify `.$type<..>()` for json object inference, it **won't** check runtime values. 
It provides compile time protection for default values, insert and select schemas.
```typescript
// will be inferred as { foo: string }
json: json().$type<{ foo: string }>();

// will be inferred as string[]
json: json().$type<string[]>();

// won't compile
json: json().$type<string[]>().default({});
```

## ---

### enum

<Section>
```typescript
import { singlestoreEnum, singlestoreTable } from "drizzle-orm/singlestore-core";

const table = singlestoreTable('table', {
	popularity: singlestoreEnum(['unknown', 'known', 'popular']),
});
```

```sql
CREATE TABLE `table` (
	`popularity` enum('unknown','known','popular')
);
```
</Section>

## ---

### Customizing data type

Every column builder has a `.$type()` method, which allows you to customize the data type of the column. This is useful, for example, with unknown or branded types.

```ts
type UserId = number & { __brand: 'user_id' };
type Data = {
	foo: string;
	bar: number;
};

const users = singlestoreTable('users', {
  id: int().$type<UserId>().primaryKey(),
  jsonField: json().$type<Data>(),
});
```

### Not null
`NOT NULL` constraint dictates that the associated column may not contain a `NULL` value.

<Section>
```typescript
import { int, singlestoreTable } from "drizzle-orm/singlestore-core";

const table = singlestoreTable('table', {
	int: int().notNull(),
});
```

```sql
CREATE TABLE `table` (
	`int` int NOT NULL
);
```
</Section>

### Default value

The `DEFAULT` clause specifies a default value to use for the column if no value
is explicitly provided by the user when doing an `INSERT`.
If there is no explicit `DEFAULT` clause attached to a column definition,
then the default value of the column is `NULL`.

An explicit `DEFAULT` clause may specify that the default value is `NULL`,
a string constant, a blob constant, a signed-number, or any constant expression enclosed in parentheses.

<Section>
```typescript
import { int, singlestoreTable } from "drizzle-orm/singlestore-core";

const table = singlestoreTable('table', {
	int: int().default(3),
});
```

```sql
CREATE TABLE `table` (
	`int` int DEFAULT 3
);
```
</Section>

When using `$default()` or `$defaultFn()`, which are simply different aliases for the same function, 
you can generate defaults at runtime and use these values in all insert queries. 
These functions can assist you in utilizing various implementations such as `uuid`, `cuid`, `cuid2`, and many more.

<Callout type="info" emoji="ℹ️">
	Note: This value does not affect the `drizzle-kit` behavior, it is only used at runtime in `drizzle-orm`
</Callout>

```ts
import { varchar, singlestoreTable } from "drizzle-orm/singlestore-core";
import { createId } from '@paralleldrive/cuid2';

const table = singlestoreTable('table', {
	id: varchar({ length: 128 }).$defaultFn(() => createId()),
});
```

When using `$onUpdate()` or `$onUpdateFn()`, which are simply different aliases for the same function, 
you can generate defaults at runtime and use these values in all update queries. 

Adds a dynamic update value to the column. The function will be called when the row is updated, 
and the returned value will be used as the column value if none is provided.
If no default (or $defaultFn) value is provided, the function will be called
when the row is inserted as well, and the returned value will be used as the column value.

<Callout type="info" emoji="ℹ️">
	Note: This value does not affect the `drizzle-kit` behavior, it is only used at runtime in `drizzle-orm`
</Callout>

```ts
import { text, singlestoreTable } from "drizzle-orm/singlestore-core";

const table = singlestoreTable('table', {
    alwaysNull: text().$type<string | null>().$onUpdate(() => null),
});
```

### Primary key 

<Section>
```typescript
import { int, singlestoreTable } from "drizzle-orm/singlestore-core";

const table = singlestoreTable('table', {
	int: int().primaryKey(),
});
```

```sql
CREATE TABLE `table` (
	`int` int PRIMARY KEY NOT NULL
);
```
</Section>

### Auto increment

<Section>
```typescript
import { int, singlestoreTable } from "drizzle-orm/singlestore-core";

const table = singlestoreTable('table', {
	int: int().autoincrement(),
});
```

```sql
CREATE TABLE `table` (
	`int` int AUTO_INCREMENT
);
```
</Section>


Source: https://orm.drizzle.team/docs/singlestore/connect-overview

# Database connection with Drizzle

Use the SingleStore driver with Drizzle ORM.

## SingleStore connection docs

- [SingleStore](/docs/singlestore/get-started-singlestore)


Source: https://orm.drizzle.team/docs/singlestore/custom-types

# Custom types

SingleStore exposes `customType` from `drizzle-orm/singlestore-core`.

```ts
import { customType, singlestoreTable } from 'drizzle-orm/singlestore-core';

const customText = customType<{ data: string }>({
  dataType() {
    return 'text';
  },
});

export const users = singlestoreTable('users', {
  name: customText('name').notNull(),
});
```


Source: https://orm.drizzle.team/docs/singlestore/delete

import Callout from '@mdx/Callout.astro';
import Section from '@mdx/Section.astro';

# SQL Delete
You can delete all rows in the table:
```typescript copy
await db.delete(users);
```
And you can delete with filters and conditions:
```typescript copy
await db.delete(users).where(eq(users.name, 'Dan'));
```

### Limit
Use `.limit()` to add `limit` clause to the query - for example:
<Section>
```typescript
await db.delete(users).where(eq(users.name, 'Dan')).limit(2);
```
```sql
delete from `users` where `users`.`name` = ? limit ?;
```
</Section>

### Order By
Use `.orderBy()` to add `order by` clause to the query, sorting the results by the specified fields:
<Section>
```typescript
import { asc, desc } from 'drizzle-orm';

await db.delete(users).where(eq(users.name, 'Dan')).orderBy(users.name);
await db.delete(users).where(eq(users.name, 'Dan')).orderBy(desc(users.name));

// order by multiple fields
await db.delete(users).where(eq(users.name, 'Dan')).orderBy(users.name, users.name2);
await db.delete(users).where(eq(users.name, 'Dan')).orderBy(asc(users.name), desc(users.name2));
```
```sql
delete from `users` where `users`.`name` = ? order by `name`;
delete from `users` where `users`.`name` = ? order by `name` desc;

delete from `users` where `users`.`name` = ? order by `name`, `name2`;
delete from `users` where `users`.`name` = ? order by `name` asc, `name2` desc;
```
</Section>



Source: https://orm.drizzle.team/docs/singlestore/drizzle-config-file

import CodeTab from "@mdx/CodeTab.astro";
import CodeTabs from "@mdx/CodeTabs.astro";
import Section from "@mdx/Section.astro";
import Tab from "@mdx/Tab.astro";
import Tabs from "@mdx/Tabs.astro";
import Callout from "@mdx/Callout.astro";
import SchemaFilePaths from "@mdx/SchemaFilePaths.mdx"
import Prerequisites from "@mdx/Prerequisites.astro"
import Dialects from "@mdx/Dialects.mdx"
import Drivers from "@mdx/Drivers.mdx"
import DriversExamples from "@mdx/DriversExamples.mdx"
import Npx from "@mdx/Npx.astro"

# Drizzle Kit configuration file
<Prerequisites>
- Get started with Drizzle and `drizzle-kit` - [read here](/docs/singlestore/get-started)
- Drizzle schema fundamentals - [read here](/docs/singlestore/sql-schema-declaration)
- Database connection basics - [read here](/docs/singlestore/connect-overview)
- Drizzle migrations fundamentals - [read here](/docs/singlestore/migrations)
- Drizzle Kit [overview](/docs/singlestore/kit-overview) and [config file](/docs/singlestore/drizzle-config-file)
</Prerequisites>

Drizzle Kit lets you declare configuration options in `TypeScript` or `JavaScript` configuration files.

<Section>
```plaintext {5}
📦 <project root>
 ├ ...
 ├ 📂 drizzle
 ├ 📂 src
 ├ 📜 drizzle.config.ts
 └ 📜 package.json
```
<CodeTabs items={["drizzle.config.ts", "drizzle.config.js"]}>
<CodeTab>
```ts
import { defineConfig } from "drizzle-kit";

export default defineConfig({
  dialect: "singlestore",
  schema: "./src/schema.ts",
  out: "./drizzle",
});
```
</CodeTab>
<CodeTab>
```js
import { defineConfig } from "drizzle-kit";

export default defineConfig({
  dialect: "singlestore",
  schema: "./src/schema.ts",
  out: "./drizzle",
});
```
</CodeTab>
</CodeTabs>
</Section>

Example of an extended config file
```ts collapsable
import { defineConfig } from "drizzle-kit";

export default defineConfig({
  out: "./drizzle",
  dialect: "singlestore",
  schema: "./src/schema.ts",

  dbCredentials: {
    url: "mysql://user:password@host:3306/dbname",
  },

  introspect: {
    casing: "camel",
  },

  migrations: {
    prefix: "timestamp",
    table: "__drizzle_migrations__",
  },

  breakpoints: true,
  strict: true,
  verbose: true,
});
```

### Multiple configuration files
You can have multiple config files in the project, it's very useful when you have multiple database stages or multiple databases or different databases on the same project:
<Npx>
  drizzle-kit generate --config=drizzle-dev.config.ts
  drizzle-kit generate --config=drizzle-prod.config.ts
</Npx>
```plaintext {5-6}
📦 <project root>
 ├ 📂 drizzle
 ├ 📂 src
 ├ 📜 .env
 ├ 📜 drizzle-dev.config.ts
 ├ 📜 drizzle-prod.config.ts
 ├ 📜 package.json
 └ 📜 tsconfig.json
```

### Migrations folder
`out` param lets you define folder for your migrations, it's optional and `drizzle` by default.  
It's very useful since you can have many separate schemas for different databases in the same project 
and have different migration folders for them.  
  
Migration folder contains folders with `.sql` migration files which is used by `drizzle-kit`

<Section>
```plaintext {3}
📦 <project root>
 ├ ...
 ├ 📂 drizzle
 │ ├ 📂 20242409125510_premium_mister_fear
 │ ├ 📜 user.ts 
 │ ├ 📜 post.ts 
 │ └ 📜 comment.ts 
 ├ 📂 src
 ├ 📜 drizzle.config.ts
 └ 📜 package.json
```
```ts {5}
import { defineConfig } from "drizzle-kit";

export default defineConfig({
  dialect: "singlestore", // "mysql" | "sqlite" | "postgresql" | "turso" | "singlestore" | "mssql"
  schema: "./src/schema/*",
  out: "./drizzle",
});
```
</Section>

## ---

### `dialect`
<rem025/>

Dialect of the database you're using 
|               |                                                 |
| :------------ | :-----------------------------------            |
| type        | <Dialects/>                                     |
| default        | --                                     |
| commands    | `generate` `migrate` `push` `pull` `check` `up` |

<rem025/>
```ts {4}
import { defineConfig } from "drizzle-kit";

export default defineConfig({
  dialect: "mysql", 
});
```


### `schema`
<rem025/>

[`glob`](https://www.digitalocean.com/community/tools/glob?comments=true&glob=/**/*.js&matches=false&tests=//%20This%20will%20match%20as%20it%20ends%20with%20'.js'&tests=/hello/world.js&tests=//%20This%20won't%20match!&tests=/test/some/globs)
 based path to drizzle schema file(s) or folder(s) contaning schema files.
|               |                      |
| :------------ | :-----------------   |
| type          | `string` `string[]` |
| default        | --                    |
| commands      | `generate` `push`    |

<rem025/>
<SchemaFilePaths />


### `out`
<rem025/>

Defines output folder of your SQL migration files, json snapshots of your schema and `schema.ts` from `drizzle-kit pull` command.
|               |                      |
| :------------ | :-----------------   |
| type          | `string` `string[]` |
| default        | `drizzle`                    |
| commands      | `generate` `migrate` `push` `pull` `check` `up`    |

<rem025/>
```ts {4}
import { defineConfig } from "drizzle-kit";

export default defineConfig({
  out: "./drizzle", 
});
```

### `driver`
<rem025/>

Drizzle Kit automatically picks an available SingleStore driver from your current project based on `dialect: "singlestore"`.
SingleStore uses MySQL-compatible connection parameters, so you usually do not need a separate `driver` option.

|               |                      |
| :------------ | :-----------------   |
| type          | --                    |
| default       | --                    |
| commands      | `migrate` `push` `pull`   |

## ---

### `dbCredentials`
<rem025/>

Database connection credentials in a form of `url`, 
`user:password@host:port/db` params or exceptions drivers(<Drivers/>) specific connection options.

|               |                      |
| :------------ | :-----------------   |
| type          | union of drivers connection options |
| default       | --                    |
| commands      | `migrate` `push` `pull`   |

<rem025/>

<CodeTabs items={["Connection string", "Connection params"]}>
<Section>
```ts
import { defineConfig } from 'drizzle-kit'

export default defineConfig({
  dialect: "singlestore",
  dbCredentials: {
    url: "mysql://user:password@host:3306/db",
  }
});
```
</Section>
<Section>
```ts
import { defineConfig } from 'drizzle-kit'

export default defineConfig({
  dialect: "singlestore",
  dbCredentials: {
    host: "host",
    port: 3306,
    user: "user",
    password: "password",
    database: "dbname",
    ssl: "...", // can be: string | SslOptions from mysql2
  }
});
```
</Section>
</CodeTabs>

### `migrations`
<rem025/>

When running `drizzle-kit migrate` - drizzle will records about 
successfully applied migrations in your database in log table named `__drizzle_migrations`.

`migrations` config options lets you change the migrations log `table` name.

|               |                      |
| :------------ | :-----------------   |
| type          | `{ table: string }` |
| default       | `{ table: "__drizzle_migrations" }`                    |
| commands      | `migrate`   |

<rem025/>

```ts
export default defineConfig({
  dialect: "singlestore",
  schema: "./src/schema.ts",
  migrations: {
    table: 'my-migrations-table', // `__drizzle_migrations` by default
  },
});
```

### `introspect`
<rem025/>

Configuration for `drizzle-kit pull` command.

`casing` is responsible for in-code column keys casing

|               |                      |
| :------------ | :-----------------   |
| type          | `{ casing: "preserve" \| "camel" }` |
| default       | `{ casing: "camel" }`                    |
| commands      | `pull`   |

<rem025/>

<CodeTabs items={["camel", "preserve"]}>
<Section>
```ts
import * as p from "drizzle-orm/singlestore-core"

export const users = p.singlestoreTable("users", {
  id: p.int().primaryKey().autoincrement(),
  firstName: p.varchar("first-name", { length: 255 }),
  lastName: p.varchar("LastName", { length: 255 }),
  email: p.varchar("email", { length: 255 }),
  phoneNumber: p.varchar("phone_number", { length: 255 }),
});
```
```sql
SHOW COLUMNS FROM users;
```
```
  Field        | Type
--------------+--------------
 id           | int
 first-name   | varchar(255)
 LastName     | varchar(255)
 email        | varchar(255)
 phone_number | varchar(255)
```
</Section>
<Section>
```ts
import * as p from "drizzle-orm/singlestore-core"

export const users = p.singlestoreTable("users", {
  id: p.int().primaryKey().autoincrement(),
  "first-name": p.varchar("first-name", { length: 255 }),
  LastName: p.varchar("LastName", { length: 255 }),
  email: p.varchar("email", { length: 255 }),
  phone_number: p.varchar("phone_number", { length: 255 }),
});
```
```sql
SHOW COLUMNS FROM users;
```
```
  Field        | Type
--------------+--------------
 id           | int
 first-name   | varchar(255)
 LastName     | varchar(255)
 email        | varchar(255)
 phone_number | varchar(255)
```
</Section>
</CodeTabs>


## --- 

### `tablesFilter`
<Callout>
If you want to run multiple projects with one database - check out [our guide](/docs/singlestore/goodies#multi-project-schema).
</Callout>
<rem025/>
`drizzle-kit push` and `drizzle-kit pull` will manage all tables by default.
You can configure the list of tables via `tablesFilter`.

`tablesFilter` option lets you specify [`glob`](https://www.digitalocean.com/community/tools/glob?comments=true&glob=/**/*.js&matches=false&tests=//%20This%20will%20match%20as%20it%20ends%20with%20'.js'&tests=/hello/world.js&tests=//%20This%20won't%20match!&tests=/test/some/globs) 
based table names filter, e.g. `["users", "user_info"]` or `"user*"`

|               |                      |
| :------------ | :-----------------   |
| type          | `string` `string[]` |
| default       | --                    |
| commands      | `generate` `push` `pull`   |

<rem025/>
```ts
import { defineConfig } from "drizzle-kit";

export default defineConfig({
  dialect: "singlestore",
  tablesFilter: ["users", "posts", "project1_*"],
});
```

## ---

### `strict`
<rem025/>

Prompts confirmation to run printed SQL statements when running `drizzle-kit push` command.

|               |                      |
| :------------ | :-----------------   |
| type          | `boolean` |
| default       | `false`                    |
| commands      | `push`   |

<rem025/>

```ts
export default defineConfig({
  dialect: "singlestore",
  strict: false,
});
```

### `verbose`
<rem025/>

Print all SQL statements during `drizzle-kit push` command.

|               |                      |
| :------------ | :-----------------   |
| type          | `boolean` |
| default       | `true`                    |
| commands      | `generate` `pull`   |

<rem025/>

```ts
export default defineConfig({
  dialect: "singlestore",
  verbose: false,
});
```

### `breakpoints`
<rem025/>

Drizzle Kit will automatically embed `--> statement-breakpoint` into generated SQL migration files, 
that's necessary for databases that do not support multiple DDL alternation statements in one transaction(MySQL and SQLite).

`breakpoints` option flag lets you switch it on and off

|               |                      |
| :------------ | :-----------------   |
| type          | `boolean` |
| default       | `true`                    |
| commands      | `generate` `pull`   |

<rem025/>

```ts
export default defineConfig({
  dialect: "singlestore",
  breakpoints: false,
});
```


Source: https://orm.drizzle.team/docs/singlestore/drizzle-kit-check

import CodeTab from "@mdx/CodeTab.astro";
import CodeTabs from "@mdx/CodeTabs.astro";
import Section from "@mdx/Section.astro";
import Tab from "@mdx/Tab.astro";
import Tabs from "@mdx/Tabs.astro";
import Callout from "@mdx/Callout.astro";
import Prerequisites from "@mdx/Prerequisites.astro";
import Npm from "@mdx/Npm.astro";
import Npx from "@mdx/Npx.astro";


# `drizzle-kit check`

<Prerequisites>
- Get started with Drizzle and `drizzle-kit` - [read here](/docs/singlestore/get-started)
- Drizzle schema fundamentals - [read here](/docs/singlestore/sql-schema-declaration)
- Database connection basics - [read here](/docs/singlestore/connect-overview)
- Drizzle migrations fundamentals - [read here](/docs/singlestore/migrations)
- Drizzle Kit [overview](/docs/singlestore/kit-overview) and [config file](/docs/singlestore/drizzle-config-file)
- `drizzle-kit generate` command - [read here](/docs/singlestore/drizzle-kit-generate)
</Prerequisites>

`drizzle-kit check` command lets you check consistency of your generated SQL migrations history.

That's extremely useful when you have multiple developers working on the project and 
altering database schema on different branches - read more about [migrations for teams](/docs/singlestore/kit-migrations-for-teams).

<br/>
<hr/>
<br/>

`drizzle-kit check` command requires you to specify both `dialect` and database connection credentials, 
you can provide them either via [drizzle.config.ts](/docs/singlestore/drizzle-config-file) config file or via CLI options

<CodeTabs items={["With config file", "As CLI options"]}>
<Section>
```ts {5,8}
// drizzle.config.ts
import { defineConfig } from "drizzle-kit";

export default defineConfig({
  dialect: "singlestore",
});
```
```shell
npx drizzle-kit check
```
</Section>
```shell
npx drizzle-kit check --dialect=singlestore
```
</CodeTabs>

### Multiple configuration files in one project
You can have multiple config files in the project, it's very useful when you have multiple database stages or multiple databases on the same project:
<Npx>
  drizzle-kit check --config=drizzle-dev.config.ts
  drizzle-kit check --config=drizzle-prod.config.ts
</Npx>
```plaintext {5-6}
📦 <project root>
 ├ 📂 drizzle
 ├ 📂 src
 ├ 📜 .env
 ├ 📜 drizzle-dev.config.ts
 ├ 📜 drizzle-prod.config.ts
 ├ 📜 package.json
 └ 📜 tsconfig.json
```

### Extended list of configurations
We recommend configuring `drizzle-kit` through [drizzle.config.ts](/docs/singlestore/drizzle-config-file) file, 
yet you can provide all configuration options through CLI if necessary, e.g. in CI/CD pipelines, etc.
<rem025/>
|           |            |                                                                         |
| :-------- | :--------- | :---------------------------------------------------------------------- |
| `dialect` | `required` | Database dialect you are using. Can be `postgresql`, `mysql`, `sqlite`, or `singlestore` |
| `out`     |            | Migrations folder, default=`./drizzle`                                  |
| `config`  |            | Configuration file path, default=`drizzle.config.ts`                           |
<br/>
<Npx>
drizzle-kit check --dialect=singlestore
drizzle-kit check --dialect=singlestore --out=./migrations-folder
</Npx>


Source: https://orm.drizzle.team/docs/singlestore/drizzle-kit-export

import CodeTab from "@mdx/CodeTab.astro";
import CodeTabs from "@mdx/CodeTabs.astro";
import Section from "@mdx/Section.astro";
import Tab from "@mdx/Tab.astro";
import Tabs from "@mdx/Tabs.astro";
import Callout from "@mdx/Callout.astro";
import Prerequisites from "@mdx/Prerequisites.astro"
import Npx from "@mdx/Npx.astro";
import SchemaFilePaths from "@mdx/SchemaFilePaths.mdx"
import Dialects from "@mdx/Dialects.mdx"

# `drizzle-kit export` 

<Prerequisites>
- Get started with Drizzle and `drizzle-kit` - [read here](/docs/singlestore/get-started)
- Drizzle schema fundamentals - [read here](/docs/singlestore/sql-schema-declaration)
- Database connection basics - [read here](/docs/singlestore/connect-overview)
- Drizzle migrations fundamentals - [read here](/docs/singlestore/migrations)
- Drizzle Kit [overview](/docs/singlestore/kit-overview) and [config file](/docs/singlestore/drizzle-config-file)
</Prerequisites>


<br/>

`drizzle-kit export` lets you export SQL representation of Drizzle schema and print in console SQL DDL representation on it.
<Callout collapsed="How it works under the hood?">
Drizzle Kit `export` command triggers a sequence of events:
1. It will read through your Drizzle schema file(s) and compose a json snapshot of your schema
3. Based on json differences it will generate SQL DDL statements
4. Output SQL DDL statements to console
</Callout>

It's designed to cover [codebase first](/docs/singlestore/migrations) approach of managing Drizzle migrations. 
You can export the SQL representation of the Drizzle schema, allowing external tools like Atlas to handle all the migrations for you

`drizzle-kit export` command requires you to provide both `dialect` and `schema` path options, 
you can set them either via [drizzle.config.ts](/docs/singlestore/drizzle-config-file) config file or via CLI options
<CodeTabs items={["With config file", "As CLI options"]}>
<Section>
```ts
// drizzle.config.ts
import { defineConfig } from "drizzle-kit";

export default defineConfig({
  dialect: "singlestore",
  schema: "./src/schema.ts",
});
```
```shell
npx drizzle-kit export
```
</Section>

```shell
npx drizzle-kit export --dialect=singlestore --schema=./src/schema.ts
```
</CodeTabs>

### Schema files path
You can have a single `schema.ts` file or as many schema files as you want spread out across the project. 
Drizzle Kit requires you to specify path(s) to them as a [glob](https://www.digitalocean.com/community/tools/glob?comments=true&glob=/**/*.js&matches=false&tests=//%20This%20will%20match%20as%20it%20ends%20with%20'.js'&tests=/hello/world.js&tests=//%20This%20won't%20match!&tests=/test/some/globs) via `schema` configuration option.

<SchemaFilePaths/>

### Multiple configuration files in one project
You can have multiple config files in the project, it's very useful when you have multiple database stages or multiple databases or different databases on the same project:
<Npx>
  drizzle-kit export --config=drizzle-dev.config.ts
  drizzle-kit export --config=drizzle-prod.config.ts
</Npx>
```plaintext {5-6}
📦 <project root>
 ├ 📂 drizzle
 ├ 📂 src
 ├ 📜 .env
 ├ 📜 drizzle-dev.config.ts
 ├ 📜 drizzle-prod.config.ts
 ├ 📜 package.json
 └ 📜 tsconfig.json
```

### Extended list of available configurations
`drizzle-kit export` has a list of cli-only options

<rem025/>

|               |                                                      |
| :--------     | :--------------------------------------------------- |
| `--sql`       | generating SQL representation of Drizzle Schema               |

By default, Drizzle Kit outputs SQL files, but in the future, we want to support different formats

<rem025/>

<Npx>
drizzle-kit push --name=init
drizzle-kit push --name=seed_users --custom
</Npx>

<br/>
<hr/>
<br/>
We recommend configuring `drizzle-kit` through [drizzle.config.ts](/docs/singlestore/drizzle-config-file) file, 
yet you can provide all configuration options through CLI if necessary, e.g. in CI/CD pipelines, etc.

|               |            |                                                                            |
| :------------ | :-------   | :----------------------------------------------------------------------    |
| `dialect`     | `required` | Database dialect, one of <Dialects/>                                       |
| `schema`      | `required` | Path to typescript schema file(s) or folder(s) with multiple schema files  |
| `config`      |            | Configuration file path, default is `drizzle.config.ts`                    |

### Example
Example of how to export drizzle schema to console with Drizzle schema located in `./src/schema.ts`

We will also place drizzle config file in the `configs` folder.

Let's create config file:

```plaintext {4}
📦 <project root>
 ├ 📂 configs
 │ └ 📜 drizzle.config.ts
 ├ 📂 src
 │ └ 📜 schema.ts
 └ …
```
```ts filename='drizzle.config.ts'
import { defineConfig } from "drizzle-kit";

export default defineConfig({
  dialect: "singlestore",
  schema: "./src/schema.ts",
});
```

```ts filename='schema.ts'
import { singlestoreTable, serial, text } from 'drizzle-orm/singlestore-core'

export const users = singlestoreTable('users', {
	id: int('id').primaryKey().autoincrement(),
	email: text('email').notNull(),
	name: text('name')
});
```

Now let's run
```shell
npx drizzle-kit export --config=./configs/drizzle.config.ts
```
And it will successfully output SQL representation of drizzle schema
```bash
CREATE TABLE "users" (
        `id` int auto_increment primary key not null,
        `email` varchar(255) not null,
        "name" text
);
```

Source: https://orm.drizzle.team/docs/singlestore/drizzle-kit-generate

import CodeTab from "@mdx/CodeTab.astro";
import CodeTabs from "@mdx/CodeTabs.astro";
import Section from "@mdx/Section.astro";
import Tab from "@mdx/Tab.astro";
import Tabs from "@mdx/Tabs.astro";
import Callout from "@mdx/Callout.astro";
import Prerequisites from "@mdx/Prerequisites.astro"
import Npx from "@mdx/Npx.astro";
import SchemaFilePaths from "@mdx/SchemaFilePaths.mdx"
import Dialects from "@mdx/Dialects.mdx"

# `drizzle-kit generate` 

<Prerequisites>
- Get started with Drizzle and `drizzle-kit` - [read here](/docs/singlestore/get-started)
- Drizzle schema fundamentals - [read here](/docs/singlestore/sql-schema-declaration)
- Database connection basics - [read here](/docs/singlestore/connect-overview)
- Drizzle migrations fundamentals - [read here](/docs/singlestore/migrations)
- Drizzle Kit [overview](/docs/singlestore/kit-overview) and [config file](/docs/singlestore/drizzle-config-file)
</Prerequisites>


<br/>

`drizzle-kit generate` lets you generate SQL migrations based on your Drizzle schema upon declaration or on subsequent schema changes.
<Callout collapsed="How it works under the hood?">
Drizzle Kit `generate` command triggers a sequence of events:
1. It will read through your Drizzle schema file(s) and compose a json snapshot of your schema
2. It will read through your previous migrations folders and compare current json snapshot to the most recent one
3. Based on json differences it will generate SQL migrations
4. Save `migration.sql` and `snapshot.json` in migration folder under current timestamp

<Section>
```typescript filename="src/schema.ts"
import * as p from "drizzle-orm/singlestore-core";

export const users = p.singlestoreTable("users", {
  id: p.int().primaryKey().autoincrement(),
  name: p.varchar({ length: 255 }),
  email: p.varchar({ length: 255 }).unique(), 
};
```
```                                  
┌────────────────────────┐                  
│ $ drizzle-kit generate │                  
└─┬──────────────────────┘                  
  │                                           
  └ 1. read previous migration folders
    2. find diff between current and previous schema
    3. prompt developer for renames if necessary
  ┌ 4. generate SQL migration and persist to file
  │    ┌─┴───────────────────────────────────────┐  
  │      📂 drizzle       
  │      └ 📂 20242409125510_premium_mister_fear
  │        ├ 📜 migration.sql
  │        └ 📜 snapshot.json
  v
```
```sql
-- drizzle/20242409125510_premium_mister_fear/migration.sql

CREATE TABLE `users` (
 `id` int auto_increment primary key,
 `name` varchar(255),
 `email` varchar(255) unique
);
```
</Section>
</Callout>

It's designed to cover [code first](/docs/singlestore/migrations) approach of managing Drizzle migrations. 
You can apply generated migrations using [`drizzle-kit migrate`](/docs/singlestore/drizzle-kit-migrate), using drizzle-orm's `migrate()`, 
using external migration tools like [bytebase](https://www.bytebase.com/) or running migrations yourself directly on the database. 

`drizzle-kit generate` command requires you to provide both `dialect` and `schema` path options, 
you can set them either via [drizzle.config.ts](/docs/singlestore/drizzle-config-file) config file or via CLI options
<CodeTabs items={["With config file", "As CLI options"]}>
<Section>
```ts
// drizzle.config.ts
import { defineConfig } from "drizzle-kit";

export default defineConfig({
  dialect: "singlestore",
  schema: "./src/schema.ts",
});
```
```shell
npx drizzle-kit generate
```
</Section>

```shell
npx drizzle-kit generate --dialect=singlestore --schema=./src/schema.ts
```
</CodeTabs>

### Schema files path
You can have a single `schema.ts` file or as many schema files as you want spread out across the project. 
Drizzle Kit requires you to specify path(s) to them as a [glob](https://www.digitalocean.com/community/tools/glob?comments=true&glob=/**/*.js&matches=false&tests=//%20This%20will%20match%20as%20it%20ends%20with%20'.js'&tests=/hello/world.js&tests=//%20This%20won't%20match!&tests=/test/some/globs) via `schema` configuration option.

<SchemaFilePaths/>


### Custom migration file name
You can set custom migration file names by providing `--name` CLI option
```shell
npx drizzle-kit generate --name=init
```
```plaintext {4}
📦 <project root>
 ├ 📂 drizzle
 │ └ 📂 20242409125510_init
 │   ├ 📜 snapshot.json
 │   └ 📜 migration.sql
 ├ 📂 src
 └ …
```

### Multiple configuration files in one project
You can have multiple config files in the project, it's very useful when you have multiple database stages or multiple databases or different databases on the same project:
<Npx>
  drizzle-kit generate --config=drizzle-dev.config.ts
  drizzle-kit generate --config=drizzle-prod.config.ts
</Npx>
```plaintext {5-6}
📦 <project root>
 ├ 📂 drizzle
 ├ 📂 src
 ├ 📜 .env
 ├ 📜 drizzle-dev.config.ts
 ├ 📜 drizzle-prod.config.ts
 ├ 📜 package.json
 └ 📜 tsconfig.json
```

### Custom migrations
You can generate empty migration files to write your own custom SQL migrations 
for DDL alternations currently not supported by Drizzle Kit or data seeding. Extended docs on custom migrations - [see here](/docs/singlestore/kit-custom-migrations)

```shell
drizzle-kit generate --custom --name=seed-users
```
<Section>
```plaintext {5}
📦 <project root>
 ├ 📂 drizzle
 │ ├ 📂 20242409125510_init
 │ └ 📂 20242409125510_seed-users
 ├ 📂 src
 └ …
```
```sql
-- ./drizzle/20242409125510_seed/migration.sql

INSERT INTO `users` (`name`) VALUES('Dan');
INSERT INTO `users` (`name`) VALUES('Andrew');
INSERT INTO `users` (`name`) VALUES('Dandrew');
```
</Section>

### Ignore conflicts

<Callout type='warning'>
`--ignore-conflicts` available starting from `drizzle-orm@1.0.0-beta.16`
</Callout>

In case you need `generate` command to skip commutativity checks and bypass it, you can use `--ignore-conflicts`. If there is a situation you want to use it, then
there is a big chance that `drizzle-kit` didn't check migrations right and it's a bug. Please report us your case, so we can fix it

```shell
drizzle-kit generate --ignore-conflicts
```

### Extended list of available configurations
`drizzle-kit generate` has a list of cli-only options

<rem025/>

|               |                                                      |
| :--------     | :--------------------------------------------------- |
| `custom`      | generate empty SQL for custom migration              |
| `name`        | generate migration with custom name                  |
| `ignore-conflicts` | skip commutativity conflict checks, default is `false` |

<rem025/>

<Npx>
drizzle-kit generate --name=init
drizzle-kit generate --name=seed_users --custom
drizzle-kit generate --ignore-conflicts
</Npx>

<br/>
<hr/>
<br/>
We recommend configuring `drizzle-kit` through [drizzle.config.ts](/docs/singlestore/drizzle-config-file) file, 
yet you can provide all configuration options through CLI if necessary, e.g. in CI/CD pipelines, etc.

|               |            |                                                                            |
| :------------ | :-------   | :----------------------------------------------------------------------    |
| `dialect`     | `required` | Database dialect, one of <Dialects/>                                       |
| `schema`      | `required` | Path to typescript schema file(s) or folder(s) with multiple schema files  |
| `out`         |            | Migrations output folder, default is `./drizzle`                           |
| `config`      |            | Configuration file path, default is `drizzle.config.ts`                    |
| `breakpoints` |            | SQL statements breakpoints, default is `true`                              |


### Extended example
Example of how to create a custom SingleStore migration file named `0001_seed-users.sql` 
with Drizzle schema located in `./src/schema.ts` and migrations folder named `./migrations` instead of default `./drizzle`.

We will also place drizzle config file in the `configs` folder.

Let's create config file:

```plaintext {4}
📦 <project root>
 ├ 📂 migrations
 ├ 📂 configs
 │ └ 📜 drizzle.config.ts
 ├ 📂 src
 └ …
```
```ts filename='drizzle.config.ts'
import { defineConfig } from "drizzle-kit";

export default defineConfig({
  dialect: "singlestore",
  schema: "./src/schema.ts",
  out: "./migrations",
});
```

Now let's run
```shell
npx drizzle-kit generate --config=./configs/drizzle.config.ts --name=seed-users --custom
```
And it will successfully generate
<Section>
```plaintext {6}
📦 <project root>
 ├ …
 ├ 📂 migrations
 │ ├ 📂 20242409125510_init
 │ └ 📂 20242409125510_seed-users
 └ …
```
```sql
-- ./drizzle/20242409125510_seed-users/migration.sql

INSERT INTO `users` (`name`) VALUES('Dan');
INSERT INTO `users` (`name`) VALUES('Andrew');
INSERT INTO `users` (`name`) VALUES('Dandrew');
```
</Section>


Source: https://orm.drizzle.team/docs/singlestore/drizzle-kit-migrate

import CodeTab from "@mdx/CodeTab.astro";
import CodeTabs from "@mdx/CodeTabs.astro";
import Section from "@mdx/Section.astro";
import Tab from "@mdx/Tab.astro";
import Tabs from "@mdx/Tabs.astro";
import Callout from "@mdx/Callout.astro";
import Prerequisites from "@mdx/Prerequisites.astro";
import Npx from "@mdx/Npx.astro";

# `drizzle-kit migrate`
<Prerequisites>
- Get started with Drizzle and `drizzle-kit` - [read here](/docs/singlestore/get-started)
- Drizzle schema fundamentals - [read here](/docs/singlestore/sql-schema-declaration)
- Database connection basics - [read here](/docs/singlestore/connect-overview)
- Drizzle migrations fundamentals - [read here](/docs/singlestore/migrations)
- Drizzle Kit [overview](/docs/singlestore/kit-overview) and [config file](/docs/singlestore/drizzle-config-file)
- `drizzle-kit generate` command - [read here](/docs/singlestore/drizzle-kit-generate)
</Prerequisites>
<br/>


`drizzle-kit migrate` lets you apply SQL migrations generated by [`drizzle-kit generate`](/docs/singlestore/drizzle-kit-generate). 
It's designed to cover [code first(option 3)](/docs/singlestore/migrations) approach of managing Drizzle migrations. 

<Callout collapsed="How it works under the hood?">
Drizzle Kit `migrate` command triggers a sequence of events:
1. Reads through migration folder and read all `.sql` migration files
2. Connects to the database and fetches entries from drizzle migrations log table
3. Based on previously applied migrations it will decide which new migrations to run
4. Runs SQL migrations and logs applied migrations to drizzle migrations table

<Section>
```plaintext
  ├ 📂 drizzle       
  │ ├ 📂 20242409125510_premium_mister_fear
  │ └ 📂 20242409135510_delicate_professor_xavie
  └ …
```
```plaintext
┌───────────────────────┐                  
│ $ drizzle-kit migrate │                  
└─┬─────────────────────┘                  
  │                                                         ┌──────────────────────────┐                                         
  └ 1. reads migration.sql files in migrations folder       │                          │
    2. fetch migration history from database -------------> │                          │
  ┌ 3. pick previously unapplied migrations <-------------- │         DATABASE         │
  └ 4. apply new migration to the database ---------------> │                          │
                                                            │                          │
                                                            └──────────────────────────┘
[✓] done!        
```
</Section>
</Callout>

`drizzle-kit migrate` command requires you to specify both `dialect` and database connection credentials, 
you can provide them either via [drizzle.config.ts](/docs/singlestore/drizzle-config-file) config file or via CLI options

<CodeTabs items={["With config file", "As CLI options"]}>
<Section>
```ts {5,8}
// drizzle.config.ts
import { defineConfig } from "drizzle-kit";

export default defineConfig({
  dialect: "singlestore",
  schema: "./src/schema.ts",
  dbCredentials: {
    url: "mysql://user:password@host:3306/dbname"
  },
});
```
```shell
npx drizzle-kit migrate
```
</Section>
```shell
npx drizzle-kit migrate --dialect=singlestore --url=mysql://user:password@host:3306/dbname
```
</CodeTabs>

### Applied migrations log in the database
Upon running migrations Drizzle Kit will persist records about successfully applied migrations in your database. 
It will store them in migrations log table named `__drizzle_migrations`.

You can customise the **table** name of that log table via drizzle config file:
```ts filename="drizzle.config.ts" {8-9}
export default defineConfig({
  dialect: "singlestore",
  schema: "./src/schema.ts",
  dbCredentials: {
    url: "mysql://user:password@host:3306/dbname"
  },
  migrations: {
    table: 'my-migrations-table', // `__drizzle_migrations` by default
  },
});
```

### Ignore conflicts

<Callout type='warning'>
`--ignore-conflicts` available starting from `drizzle-orm@1.0.0-beta.16`
</Callout>

In case you need `migrate` command to skip commutativity checks and bypass it, you can use `--ignore-conflicts`. If there is a situation you want to use it, then
there is a big chance that `drizzle-kit` didn't check migrations right and it's a bug. Please report us your case, so we can fix it

```shell
drizzle-kit migrate --ignore-conflicts
```

### Multiple configuration files in one project
You can have multiple config files in the project, it's very useful when you have multiple database stages or multiple databases on the same project:
<Npx>
  drizzle-kit migrate --config=drizzle-dev.config.ts
  drizzle-kit migrate --config=drizzle-prod.config.ts
</Npx>
```plaintext {5-6}
📦 <project root>
 ├ 📂 drizzle
 ├ 📂 src
 ├ 📜 .env
 ├ 📜 drizzle-dev.config.ts
 ├ 📜 drizzle-prod.config.ts
 ├ 📜 package.json
 └ 📜 tsconfig.json
```

### Extended example
Let's generate SQL migration and apply it to our database using `drizzle-kit generate` and `drizzle-kit migrate` commands

```plaintext
📦 <project root>
 ├ 📂 drizzle
 ├ 📂 src
 │ ├ 📜 schema.ts
 │ └ 📜 index.ts
 ├ 📜 drizzle.config.ts
 └ …
```
<CodeTabs items={["drizzle.config.ts", "src/schema.ts"]}>
```ts
import { defineConfig } from "drizzle-kit";

export default defineConfig({
  dialect: "singlestore",
  schema: "./src/schema.ts",
  dbCredentials: {
    url: "mysql://user:password@host:3306/dbname"
  },
  migrations: {
    table: 'journal', 
  },
});
```
```ts 
import * as p from "drizzle-orm/singlestore-core";

export const users = p.singlestoreTable("users", {
  id: p.int().primaryKey().autoincrement(),
  name: p.varchar({ length: 255 }),
})
```
</CodeTabs>

Now let's run
```shell
npx drizzle-kit generate --name=init
```
it will generate
<Section>
```plaintext {5}
📦 <project root>
 ├ …
 ├ 📂 migrations
 │ ├ 📂 20242409125510_init
 └ …
```
```sql
-- ./drizzle/0000_init.sql

CREATE TABLE `users`(
  `id` int auto_increment primary key,
  `name` varchar(255)
)
```
</Section>

Now let's run
```shell
npx drizzle-kit migrate
```

and our SQL migration is now successfully applied to the database ✅


Source: https://orm.drizzle.team/docs/singlestore/drizzle-kit-pull

import CodeTab from "@mdx/CodeTab.astro";
import CodeTabs from "@mdx/CodeTabs.astro";
import Section from "@mdx/Section.astro";
import Tab from "@mdx/Tab.astro";
import Tabs from "@mdx/Tabs.astro";
import Callout from "@mdx/Callout.astro";
import Prerequisites from "@mdx/Prerequisites.astro";
import Drivers from "@mdx/Drivers.mdx"
import Dialects from "@mdx/Dialects.mdx"
import Npm from "@mdx/Npm.astro"
import Npx from "@mdx/Npx.astro"

# `drizzle-kit pull`

<Prerequisites>
- Get started with Drizzle and `drizzle-kit` - [read here](/docs/singlestore/get-started)
- Drizzle schema fundamentals - [read here](/docs/singlestore/sql-schema-declaration) 
- Database connection basics - [read here](/docs/singlestore/connect-overview) 
- Drizzle migrations fundamentals - [read here](/docs/singlestore/migrations) 
- Drizzle Kit [overview](/docs/singlestore/kit-overview) and [config file](/docs/singlestore/drizzle-config-file) docs
</Prerequisites>

`drizzle-kit pull` lets you literally pull(introspect) your existing database schema and generate `schema.ts` drizzle schema file, 
it is designed to cover [database first](/docs/singlestore/migrations) approach of Drizzle migrations.

<Callout collapsed="How it works under the hood?">
When you run Drizzle Kit `pull` command it will:
1. Pull database schema(DDL) from your existing database
2. Generate `schema.ts` drizzle schema file and save it to `out` folder

<Section>
```
                                  ┌────────────────────────┐      ┌─────────────────────────┐ 
                                  │                        │ <---  CREATE TABLE "users" (
┌──────────────────────────┐      │                        │        `id` int auto_increment primary key,
│ ~ drizzle-kit pull       │      │                        │        `name` varchar(255),
└─┬────────────────────────┘      │        DATABASE        │        `email` varchar(255) unique
  │                               │                        │       );
  └ Pull datatabase schema -----> │                        │
  ┌ Generate Drizzle       <----- │                        │
  │ schema TypeScript file        └────────────────────────┘
  │
  v
```
```typescript
import * as p from "drizzle-orm/singlestore-core";

export const users = p.singlestoreTable("users", {
  id: p.int().primaryKey().autoincrement(),
  name: p.varchar({ length: 255 }),
  email: p.varchar({ length: 255 }).unique(), 
};
```
</Section>
</Callout>

It is a great approach if you need to manage database schema outside of your TypeScript project or 
you're using database, which is managed by somebody else.

<br/>
<hr/>
<br/>

`drizzle-kit pull` requires you to specify `dialect` and either
database connection `url` or `user:password@host:port/db` params, you can provide them
either via [drizzle.config.ts](/docs/singlestore/drizzle-config-file) config file or via CLI options:

<CodeTabs items={["With config file", "With CLI options"]}>
<Section>
```ts
// drizzle.config.ts
import { defineConfig } from "drizzle-kit";

export default defineConfig({
  dialect: "singlestore",
  dbCredentials: {
    url: "mysql://user:password@host:3306/dbname",
  },
});
```
```shell
npx drizzle-kit pull
```
</Section>

```shell
npx drizzle-kit pull --dialect=singlestore --url=mysql://user:password@host:3306/dbname
```
</CodeTabs>

### Multiple configuration files in one project

You can have multiple config files in the project, it's very useful when you have multiple database stages or multiple databases or different databases on the same project:

<Npx>
  drizzle-kit pull --config=drizzle-dev.config.ts
  drizzle-kit pull --config=drizzle-prod.config.ts
</Npx>
```plaintext {5-6}
📦 <project root>
 ├ 📂 drizzle
 ├ 📂 src
 ├ 📜 .env
 ├ 📜 drizzle-dev.config.ts
 ├ 📜 drizzle-prod.config.ts
 ├ 📜 package.json
 └ 📜 tsconfig.json
```

### Specifying database driver
Drizzle Kit does not come with a pre-bundled database driver,
it will automatically pick an available SingleStore driver from your current project based on `dialect: "singlestore"` - [see discussion](https://github.com/drizzle-team/drizzle-orm/discussions/2203).

SingleStore uses MySQL-compatible connection parameters, so you usually only need to provide `dbCredentials`.

### Initial pull

<Callout type='error'>
This feature is available on  `1.0.0-beta.2` and higher.
</Callout>

<Npm>
drizzle-orm@rc
drizzle-kit@rc -D
</Npm>

<br/>

You can use the `--init` flag to mark the pulled schema as an applied migration in your database, 
so that all subsequent migrations are diffed against the initial one

```shell
npx drizzle-kit push --init
```

### Including tables
`drizzle-kit pull` will introspect all SingleStore tables by default.
You can configure the list of tables via `tablesFilter`.

|                |                                                                                               |
| :------------- | :-------------------------------------------------------------------------------------------- |
| `tablesFilter` | `glob` based table names filter, e.g. `["users", "user_info"]` or `"user*"`. Default is `"*"` |
<br/>

Let's configure drizzle-kit to introspect **all tables** in the connected SingleStore database.

<Section>
```ts filename="drizzle.config.ts" {8}
import { defineConfig } from "drizzle-kit";

export default defineConfig({
  dialect: "singlestore",
  dbCredentials: {
    url: "mysql://user:password@host:3306/dbname",
  },
  tablesFilter: ["*"],
});
```
```shell
npx drizzle-kit pull
```
</Section>

### Extended list of configurations
We recommend configuring `drizzle-kit` through [drizzle.config.ts](/docs/singlestore/drizzle-config-file) file, 
yet you can provide all configuration options through CLI if necessary, e.g. in CI/CD pipelines, etc.

|                     |            |                                                                           |
| :------------------ | :--------- | :------------------------------------------------------------------------ |
| `dialect`           | `required` | Database dialect, one of <Dialects/>                                      |
| `out`               |            | Migrations output folder path, default is `./drizzle`                     |
| `url`               |            | Database connection string                                                |
| `user`              |            | Database user                                                             |
| `password`          |            | Database password                                                         |
| `host`              |            | Host                                                                      |
| `port`              |            | Port                                                                      |
| `database`          |            | Database name                                                             |
| `config`            |            | Configuration file path, default is `drizzle.config.ts`                          |
| `introspect-casing` |            | Strategy for JS keys creation in columns, tables, etc. `preserve` `camel` |
| `tablesFilter`      |            | Table name filter                                                         |

<Npx>
drizzle-kit pull --dialect=singlestore --url=mysql://user:password@host:3306/dbname
drizzle-kit pull --dialect=singlestore --tablesFilter='user*' url=mysql://user:password@host:3306/dbname
</Npx>

![](@/assets/gifs/introspect_mysql.gif)


Source: https://orm.drizzle.team/docs/singlestore/drizzle-kit-push

import CodeTab from "@mdx/CodeTab.astro";
import CodeTabs from "@mdx/CodeTabs.astro";
import Section from "@mdx/Section.astro";
import Tab from "@mdx/Tab.astro";
import Tabs from "@mdx/Tabs.astro";
import Callout from "@mdx/Callout.astro";
import Prerequisites from "@mdx/Prerequisites.astro";
import Npx from "@mdx/Npx.astro";
import SchemaFilePaths from "@mdx/SchemaFilePaths.mdx";
import Drivers from "@mdx/Drivers.mdx"
import Dialects from "@mdx/Dialects.mdx"
import DriversExamples from "@mdx/DriversExamples.mdx"

# `drizzle-kit push`

<Prerequisites>
- Get started with Drizzle and `drizzle-kit` - [read here](/docs/singlestore/get-started)
- Drizzle schema fundamentals - [read here](/docs/singlestore/sql-schema-declaration) 
- Database connection basics - [read here](/docs/singlestore/connect-overview) 
- Drizzle migrations fundamentals - [read here](/docs/singlestore/migrations) 
- Drizzle Kit [overview](/docs/singlestore/kit-overview) and [config file](/docs/singlestore/drizzle-config-file) docs
</Prerequisites>


`drizzle-kit push` lets you literally push your schema and subsequent schema changes directly to the
database while omitting SQL files generation, it's designed to cover [code first](/docs/singlestore/migrations)
approach of Drizzle migrations.

<Callout collapsed="How it works under the hood?">
When you run Drizzle Kit `push` command it will:
1. Read through your Drizzle schema file(s) and compose a json snapshot of your schema
2. Pull(introspect) database schema 
3. Based on differences between those two it will generate SQL migrations
4. Apply SQL migrations to the database

<Section>
```typescript filename="src/schema.ts"
import * as p from "drizzle-orm/singlestore-core";

export const users = p.singlestoreTable("users", {
  id: p.int().primaryKey().autoincrement(),
  name: p.varchar({ length: 255 }),
};
```
```
┌─────────────────────┐                  
│ ~ drizzle-kit push  │                  
└─┬───────────────────┘                  
  │                                           ┌──────────────────────────┐
  └ Pull current datatabase schema ---------> │                          │
                                              │                          │
  ┌ Generate alternations based on diff <---- │         DATABASE         │
  │                                           │                          │
  └ Apply migrations to the database -------> │                          │
                                       │      └──────────────────────────┘
                                       │
  ┌────────────────────────────────────┴────────────────┐
   create table users(`id` int auto_increment primary key, `name` varchar(255));
```
</Section>
</Callout>

It's the best approach for rapid prototyping and we've seen dozens of teams
and solo developers successfully using it as a primary migrations flow in their production applications.
It pairs exceptionally well with blue/green deployment strategy and serverless databases like
[Planetscale](https://planetscale.com), [Neon](https://neon.tech), [Turso](https://turso.tech/drizzle) and others.

<br/>
<hr/>
<br/>


`drizzle-kit push` requires you to specify `dialect`, path to the `schema` file(s) and either
database connection `url` or `user:password@host:port/db` params, you can provide them
either via [drizzle.config.ts](/docs/singlestore/drizzle-config-file) config file or via CLI options:

<CodeTabs items={["With config file", "With CLI options"]}>
<Section>
```ts
// drizzle.config.ts
import { defineConfig } from "drizzle-kit";

export default defineConfig({
  dialect: "singlestore",
  schema: "./src/schema.ts",
  dbCredentials: {
    url: "mysql://user:password@host:3306/dbname",
  },
});
```
```shell
npx drizzle-kit push
```
</Section>

```shell
npx drizzle-kit push --dialect=singlestore --schema=./src/schema.ts --url=mysql://user:password@host:3306/dbname
```

</CodeTabs>

### Schema files path

You can have a single `schema.ts` file or as many schema files as you want spread out across the project.
Drizzle Kit requires you to specify path(s) to them as a [glob](https://www.digitalocean.com/community/tools/glob?comments=true&glob=/**/*.js&matches=false&tests=//%20This%20will%20match%20as%20it%20ends%20with%20'.js'&tests=/hello/world.js&tests=//%20This%20won't%20match!&tests=/test/some/globs) via `schema` configuration option.

<SchemaFilePaths />

### Multiple configuration files in one project

You can have multiple config files in the project, it's very useful when you have multiple database stages or multiple databases or different databases on the same project:

<Npx>
  drizzle-kit push --config=drizzle-dev.config.ts
  drizzle-kit push --config=drizzle-prod.config.ts
</Npx>
```plaintext {5-6}
📦 <project root>
 ├ 📂 drizzle
 ├ 📂 src
 ├ 📜 .env
 ├ 📜 drizzle-dev.config.ts
 ├ 📜 drizzle-prod.config.ts
 ├ 📜 package.json
 └ 📜 tsconfig.json
```

### Specifying database driver
Drizzle Kit does not come with a pre-bundled database driver,
it will automatically pick an available SingleStore driver from your current project based on `dialect: "singlestore"` - [see discussion](https://github.com/drizzle-team/drizzle-orm/discussions/2203).

SingleStore uses MySQL-compatible connection parameters, so you usually only need to provide `dbCredentials`.

### Including tables
`drizzle-kit push` will manage all SingleStore tables by default.
You can configure the list of tables via `tablesFilter`.

|                |                                                                                               |
| :------------- | :-------------------------------------------------------------------------------------------- |
| `tablesFilter` | `glob` based table names filter, e.g. `["users", "user_info"]` or `"user*"`. Default is `"*"` |
<br/>

Let's configure drizzle-kit to operate with **all tables** in the connected SingleStore database.

<Section>
```ts filename="drizzle.config.ts" {9}
import { defineConfig } from "drizzle-kit";

export default defineConfig({
  dialect: "singlestore",
  schema: "./src/schema.ts",
  dbCredentials: {
    url: "mysql://user:password@host:3306/dbname",
  },
  tablesFilter: ["*"],
});
```
```shell
npx drizzle-kit push
```
</Section>

### Extended list of configurations

`drizzle-kit push` has a list of cli-only options

<rem025/>

|           |                                                          |
| :-------- | :---------------------------------------------------     |
| `verbose` | print all SQL statements prior to execution              |
| `strict`  | always ask for approval before executing SQL statements  |
| `force`   | auto-accept all data-loss statements                     |
<br/>
<Npx>
drizzle-kit push --strict --verbose --force
</Npx>

<br/>
<hr/>
<br/>
We recommend configuring `drizzle-kit` through [drizzle.config.ts](/docs/singlestore/drizzle-config-file) file, 
yet you can provide all configuration options through CLI if necessary, e.g. in CI/CD pipelines, etc.

|                     |            |                                                                           |
| :------------------ | :--------- | :------------------------------------------------------------------------ |
| `dialect`           | `required` | Database dialect, one of <Dialects/>                                      |
| `schema`            | `required` | Path to typescript schema file(s) or folder(s) with multiple schema files |
| `tablesFilter`      |            | Table name filter                                                         |
| `url`               |            | Database connection string                                                |
| `user`              |            | Database user                                                             |
| `password`          |            | Database password                                                         |
| `host`              |            | Host                                                                      |
| `port`              |            | Port                                                                      |
| `database`          |            | Database name                                                             |
| `config`            |            | Configuration file path, default=`drizzle.config.ts`                             |

<Npx>
drizzle-kit push dialect=singlestore schema=src/schema.ts url=mysql://user:password@host:3306/dbname
drizzle-kit push dialect=singlestore schema=src/schema.ts --tablesFilter='user*' url=mysql://user:password@host:3306/dbname
</Npx>


### Extended example
Let's declare drizzle schema in the project and push it to the database via `drizzle-kit push` command

```plaintext
📦 <project root>
 ├ 📂 src
 │ ├ 📜 schema.ts
 │ └ 📜 index.ts
 ├ 📜 drizzle.config.ts
 └ …
```
<CodeTabs items={["drizzle.config.ts", "src/schema.ts"]}>
```ts
import { defineConfig } from "drizzle-kit";

export default defineConfig({
  dialect: "singlestore",
  schema: "./src/schema.ts",
  dbCredentials: {
    url: "mysql://user:password@host:3306/dbname"
  },
});
```
```ts 
import * as p from "drizzle-orm/singlestore-core";

export const users = p.singlestoreTable("users", {
  id: p.int().primaryKey().autoincrement(),
  name: p.varchar({ length: 255 }),
})
```
</CodeTabs>

Now let's run
```shell
npx drizzle-kit push
```

it will pull existing(empty) schema from the database and generate SQL migration and apply it under the hood
```sql
CREATE TABLE `users`(
  `id` int auto_increment primary key,
  `name` varchar(255)
)
```

DONE ✅


Source: https://orm.drizzle.team/docs/singlestore/drizzle-kit-studio

import CodeTab from "@mdx/CodeTab.astro";
import CodeTabs from "@mdx/CodeTabs.astro";
import Section from "@mdx/Section.astro";
import Tab from "@mdx/Tab.astro";
import Tabs from "@mdx/Tabs.astro";
import Callout from "@mdx/Callout.astro";
import Prerequisites from "@mdx/Prerequisites.astro";
import Npm from "@mdx/Npm.astro";
import Npx from "@mdx/Npx.astro";


# `drizzle-kit studio`
<Prerequisites>
- Drizzle Kit [overview](/docs/singlestore/kit-overview) and [config file](/docs/singlestore/drizzle-config-file)
- Drizzle Studio, our database browser - [read here](/drizzle-studio/overview)
</Prerequisites>

`drizzle-kit studio` command spins up a server for [Drizzle Studio](/drizzle-studio/overview) hosted on [local.drizzle.studio](https://local.drizzle.studio). 
It requires you to specify database connection credentials via [drizzle.config.ts](/docs/singlestore/drizzle-config-file) config file.

By default it will start a Drizzle Studio server on `127.0.0.1:4983`
<Section>
```ts {6}
// drizzle.config.ts
import { defineConfig } from "drizzle-kit";

export default defineConfig({
  dialect: "singlestore",
  dbCredentials: {
    url: "mysql://user:password@host:3306/dbname"
  },
});
```
```shell
npx drizzle-kit migrate
```
</Section>

### Configuring `host` and `port`
By default Drizzle Studio server starts on `127.0.0.1:4983`, 
you can config `host` and `port` via CLI options

<Npx>
drizzle-kit studio --port=3000
drizzle-kit studio --host=0.0.0.0
drizzle-kit studio --host=0.0.0.0 --port=3000
</Npx>


### Logging
You can enable logging of every SQL statement by providing `verbose` flag

<Npx>
drizzle-kit studio --verbose
</Npx>

### Safari and Brave support
Safari and Brave block access to localhost by default. 
You need to install [mkcert](https://github.com/FiloSottile/mkcert) and generate self-signed certificate:

1. Follow the mkcert [installation steps](https://github.com/FiloSottile/mkcert#installation)
2. Run `mkcert -install`
3. Restart your `drizzle-kit studio`

### Other flavours of Drizzle Studio
Apart from `drizzle-kit studio` for local development, Drizzle Studio also comes as a self-hosted
Drizzle Gateway, a Chrome extension for serverless database vendors and an embeddable component
for your own product — check out the [Drizzle Studio overview](/drizzle-studio/overview).

### Limitations
Our hosted version Drizzle Studio is meant to be used for local development and not meant to be used on remote (VPS, etc).

If you want to deploy Drizzle Studio to your VPS — that's what
[Drizzle Gateway](/drizzle-studio/overview#drizzle-gateway) is for.

### Is it open source?
No. Drizzle ORM and Drizzle Kit are fully open sourced, while Studio is not. 

Drizzle Studio for local development is free to use forever to enrich Drizzle ecosystem, 
open sourcing one would've break our ability to provide B2B offerings and monetise it, unfortunately.


Source: https://orm.drizzle.team/docs/singlestore/drizzle-kit-up

import CodeTab from "@mdx/CodeTab.astro";
import CodeTabs from "@mdx/CodeTabs.astro";
import Section from "@mdx/Section.astro";
import Tab from "@mdx/Tab.astro";
import Tabs from "@mdx/Tabs.astro";
import Callout from "@mdx/Callout.astro";
import Prerequisites from "@mdx/Prerequisites.astro";
import Npx from "@mdx/Npx.astro";

# `drizzle-kit up`

<Prerequisites>
- Get started with Drizzle and `drizzle-kit` - [read here](/docs/singlestore/get-started)
- Drizzle schema fundamentals - [read here](/docs/singlestore/sql-schema-declaration)
- Database connection basics - [read here](/docs/singlestore/connect-overview)
- Drizzle migrations fundamentals - [read here](/docs/singlestore/migrations)
- Drizzle Kit [overview](/docs/singlestore/kit-overview) and [config file](/docs/singlestore/drizzle-config-file)
- `drizzle-kit generate` command - [read here](/docs/singlestore/drizzle-kit-generate)
</Prerequisites>

`drizzle-kit up` command lets you upgrade drizzle schema snapshots to a newer version. 
It's required whenever we introduce breaking changes to the json snapshots of the schema and upgrade the internal version.

<br/>
<hr/>
<br/>

`drizzle-kit up` command requires you to specify both `dialect` and database connection credentials, 
you can provide them either via [drizzle.config.ts](/docs/singlestore/drizzle-config-file) config file or via CLI options

<CodeTabs items={["With config file", "As CLI options"]}>
<Section>
```ts {5,8}
// drizzle.config.ts
import { defineConfig } from "drizzle-kit";

export default defineConfig({
  dialect: "singlestore",
});
```
```shell
npx drizzle-kit up
```
</Section>
```shell
npx drizzle-kit up --dialect=singlestore
```
</CodeTabs>

### Multiple configuration files in one project
You can have multiple config files in the project, it's very useful when you have multiple database stages or multiple databases on the same project:
<Npx>
  drizzle-kit migrate --config=drizzle-dev.config.ts
  drizzle-kit migrate --config=drizzle-prod.config.ts
</Npx>
```plaintext {5-6}
📦 <project root>
 ├ 📂 drizzle
 ├ 📂 src
 ├ 📜 .env
 ├ 📜 drizzle-dev.config.ts
 ├ 📜 drizzle-prod.config.ts
 ├ 📜 package.json
 └ 📜 tsconfig.json
```

### Extended list of configurations
We recommend configuring `drizzle-kit` through [drizzle.config.ts](/docs/singlestore/drizzle-config-file) file, 
yet you can provide all configuration options through CLI if necessary, e.g. in CI/CD pipelines, etc.
<rem025/>
|           |            |                                                                         |
| :-------- | :--------- | :---------------------------------------------------------------------- |
| `dialect` | `required` | Database dialect you are using. Can be `postgresql`, `mysql`, `sqlite`, or `singlestore` |
| `out`     |            | Migrations folder, default=`./drizzle`                                  |
| `config`  |            | Configuration file path, default=`drizzle.config.ts`                           |
<br/>
<Npx>
drizzle-kit up --dialect=singlestore
drizzle-kit up --dialect=singlestore --out=./migrations-folder
</Npx>

![](@/assets/gifs/up_mysql.gif)


Source: https://orm.drizzle.team/docs/singlestore/dynamic-query-building

import Callout from '@mdx/Callout.astro';

# Dynamic query building

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
```

In the previous ORM versions, when such restrictions weren't implemented, this example in particular was a source of confusion for many users, as they expected the query builder to "merge" multiple `.where()` calls into a single condition.

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 = 1,
	pageSize: number = 10,
) {
	return qb.limit(pageSize).offset((page - 1) * 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);
```

This is possible, because `PgSelect` and other similar types are specifically designed to be used in dynamic query building. They can only be used in dynamic mode.

Here is the list of all types that can be used as generic parameters in dynamic query building:

{

<table>
	<thead align='center'>
		<tr>
			<td>
				<b>Dialect</b>
			</td>
			<td colspan='4'>
				<b>Type</b>
			</td>
		</tr>
		<tr>
			<td>
				<b>Query</b>
			</td>
			<td>
				<b>Select</b>
			</td>
			<td>
				<b>Insert</b>
			</td>
			<td>
				<b>Update</b>
			</td>
			<td>
				<b>Delete</b>
			</td>
		</tr>
	</thead>
	<tbody>
		<tr align='center'>
			<td rowspan='2'>Postgres</td>
			<td>
				<code>PgSelect</code>
			</td>
			<td rowspan='2'>
				<code>PgInsert</code>
			</td>
			<td rowspan='2'>
				<code>PgUpdate</code>
			</td>
			<td rowspan='2'>
				<code>PgDelete</code>
			</td>
		</tr>
		<tr align='center'>
			<td>
				<code>PgSelectQueryBuilder</code>
			</td>
		</tr>
		<tr align='center'>
			<td rowspan='2'>MySQL</td>
			<td>
				<code>MySqlSelect</code>
			</td>
			<td rowspan='2'>
				<code>MySqlInsert</code>
			</td>
			<td rowspan='2'>
				<code>MySqlUpdate</code>
			</td>
			<td rowspan='2'>
				<code>MySqlDelete</code>
			</td>
		</tr>
		<tr align='center'>
			<td>
				<code>MySqlSelectQueryBuilder</code>
			</td>
		</tr>
		<tr align='center'>
			<td rowspan='2'>SQLite</td>
			<td>
				<code>SQLiteSelect</code>
			</td>
			<td rowspan='2'>
				<code>SQLiteInsert</code>
			</td>
			<td rowspan='2'>
				<code>SQLiteUpdate</code>
			</td>
			<td rowspan='2'>
				<code>SQLiteDelete</code>
			</td>
		</tr>
		<tr align='center'>
			<td>
				<code>SQLiteSelectQueryBuilder</code>
			</td>
		</tr>
	</tbody>
</table>

}

<Callout type='info'>
	The `...QueryBuilder` types are for usage with [standalone query builder
	instances](/docs/goodies#standalone-query-builder). DB query builders are
	subclasses of them, so you can use them as well.

    ```ts
    	import { QueryBuilder } from 'drizzle-orm/pg-core';

    	function withFriends<T extends PgSelectQueryBuilder>(qb: T) {
    		return qb.leftJoin(friends, eq(friends.userId, users.id));
    	}

    	const qb = new QueryBuilder();
    	let query = qb.select().from(users).where(eq(users.id, 1)).$dynamic();
    	query = withFriends(query);
    ```

</Callout>


Source: https://orm.drizzle.team/docs/singlestore/effect-schema

import Npm from '@mdx/Npm.astro';
import Callout from '@mdx/Callout.astro';

<Callout type="error">
Drizzle+Effect Schema integration is available starting from `drizzle-orm@1.0.0-beta.15`
</Callout>

# effect-schema

Allows you to generate [effect](https://effect.website/) schemas from Drizzle ORM schemas.

**Features**

- Create a select schema for tables.
- Create insert and update schemas for tables.
- Supported dialect: SingleStore.

#### Usage

```ts
import { int, singlestoreTable, text, timestamp } from 'drizzle-orm/singlestore-core';
import { createInsertSchema, createSelectSchema, createUpdateSchema } from 'drizzle-orm/effect-schema';
import { Schema } from 'effect';

const users = singlestoreTable('users', {
	id: int('id').primaryKey().autoincrement(),
	name: text('name').notNull(),
	email: text('email').notNull(),
	role: text('role', { enum: ['admin', 'user'] }).notNull(),
	createdAt: timestamp('created_at').notNull().defaultNow(),
});

// Schema for inserting a user - can be used to validate API requests
const UserInsert = createInsertSchema(users);

// Schema for updating a user - can be used to validate API requests
const UserUpdate = createUpdateSchema(users);

// Schema for selecting a user - can be used to validate API responses
const UserSelect = createSelectSchema(users);

// Overriding the fields
const UserInsert = createInsertSchema(users, {
	role: Schema.String,
});

// Refining the fields - useful if you want to change the fields before they become nullable/optional in the final schema
const UserInsert = createInsertSchema(users, {
	id: (schema) => schema.pipe(Schema.greaterThanOrEqualTo(0)),
	role: Schema.String,
});

// Usage

const program = Effect.gen(function*() {
	const parsedUser = yield* Schema.validate(UserInsert)({
		name: 'John Doe',
		email: 'johndoe@test.com',
		role: 'admin',
	});
});
```

Source: https://orm.drizzle.team/docs/singlestore/extensions


import Callout from '@mdx/Callout.astro';

<Callout>
Currently, there are no SingleStore extensions natively supported by Drizzle. Once those are added, we will have them here!
</Callout>

Source: https://orm.drizzle.team/docs/singlestore/get-started-singlestore

import Npm from '@mdx/Npm.astro';
import Callout from '@mdx/Callout.astro';
import Prerequisites from "@mdx/Prerequisites.astro";
import CodeTabs from "@mdx/CodeTabs.astro";
import WhatsNextPostgres from "@mdx/WhatsNextPostgres.astro";

# Drizzle \<\> SingleStore

To use Drizzle with a SingleStore database, you should use the `mysql2` driver

Drizzle ORM natively supports `mysql2` with `drizzle-orm/singlestore` package.

#### Step 1 - Install packages
<Npm>
 drizzle-orm@rc mysql2
 -D drizzle-kit@rc
</Npm>

#### Step 2 - Initialize the driver and make a query
<CodeTabs items={['mysql2', 'mysql with config']}>
```typescript copy
import { drizzle } from "drizzle-orm/singlestore";

const db = drizzle(process.env.DATABASE_URL);

const response = await db.select().from(...)
```
```typescript copy
import { drizzle } from "drizzle-orm/singlestore";

// You can specify any property from the mysql2 connection options
const db = drizzle({ connection:{ uri: process.env.DATABASE_URL }});

const response = await db.select().from(...)
```
</CodeTabs>

If you need to provide your existing driver:

<CodeTabs items={['Client connection', 'Pool connection']}>
  ```typescript copy
  import { drizzle } from "drizzle-orm/singlestore";
  import mysql from "mysql2/promise";

  const connection = await mysql.createConnection({
    host: "host",
    user: "user",
    database: "database",
    ...
  });

  const db = drizzle({ client: connection });
  ```
  ```typescript copy
  import { drizzle } from "drizzle-orm/singlestore";
  import mysql from "mysql2/promise";

  const poolConnection = mysql.createPool({
    host: "host",
    user: "user",
    database: "database",
    ...
  });

  const db = drizzle({ client: poolConnection });
  ```
</CodeTabs>

<Callout type="warning" emoji="⚙️">
  For the built in `migrate` function with DDL migrations we and drivers strongly encourage you to use single `client` connection.  

  For querying purposes feel free to use either `client` or `pool` based on your business demands.
</Callout>

#### Limitations

Currently, the SingleStore dialect has a set of limitations and features that do not work on the SingleStore database side:

- SingleStore's serial column type only ensures the uniqueness of column values.
- `ORDER BY` and `LIMIT` cannot be chained together.
- Foreign keys are not supported (check).
- `INTERSECT ALL` and `EXCEPT ALL` operations are not supported by SingleStore.
- Nested transactions are not supported by [SingleStore](https://docs.singlestore.com/cloud/reference/sql-reference/procedural-sql-reference/transactions-in-stored-procedures/).
- SingleStore [only supports](https://docs.singlestore.com/cloud/getting-started-with-singlestore-helios/about-singlestore-helios/singlestore-helios-faqs/durability/) one `isolationLevel`.
- The FSP option in `DATE`, `TIMESTAMP`, and `DATETIME` is not supported.
- The relational API is not supported and will be implemented once the SingleStore team develops all the necessary APIs for it.
- There may be more limitations because SingleStore is not 100% compatible with MySQL.

#### What's next?

<WhatsNextPostgres/>


Source: https://orm.drizzle.team/docs/singlestore/goodies


import Callout from '@mdx/Callout.astro';
import CodeTabs from '@mdx/CodeTabs.astro';

## Type API
To retrieve a type from your table schema for `select` and `insert` queries, you can make use of our type helpers.

```ts
import { int, text, singlestoreTable } from 'drizzle-orm/singlestore-core';
import { type InferSelectModel, type InferInsertModel } from 'drizzle-orm'

const users = singlestoreTable('users', {
  id: int('id').primaryKey(),
  name: text('name').notNull(),
});

type SelectUser = typeof users.$inferSelect;
type InsertUser = typeof users.$inferInsert;
// or
type SelectUser = typeof users._.$inferSelect;
type InsertUser = typeof users._.$inferInsert;
// or
type SelectUser = InferSelectModel<typeof users>;
type InsertUser = InferInsertModel<typeof users>;
```


## Logging
To enable default query logging, just pass `{ logger: true }` to the `drizzle` initialization function:
```typescript copy
import { drizzle } from 'drizzle-orm/...'; // driver specific

const db = drizzle({ logger: true });
```

You can change the logs destination by creating a `DefaultLogger` instance and providing a custom `writer` to it:
```typescript copy
import { DefaultLogger, LogWriter } from 'drizzle-orm/logger';
import { drizzle } from 'drizzle-orm/...'; // driver specific

class MyLogWriter implements LogWriter {
  write(message: string) {
    // Write to file, stdout, etc.
  }
}

const logger = new DefaultLogger({ writer: new MyLogWriter() });
const db = drizzle({ logger });
```

You can also create a custom logger:
```typescript copy
import { Logger } from 'drizzle-orm/logger';
import { drizzle } from 'drizzle-orm/...'; // driver specific

class MyLogger implements Logger {
  logQuery(query: string, params: unknown[]): void {
    console.log({ query, params });
  }
}

const db = drizzle({ logger: new MyLogger() });
```


## Multi-project schema
**Table creator** API lets you define customize table names.  
It's very useful when you need to keep schemas of different projects in one database.

```ts {3}
import { int, text, singlestoreTableCreator } from 'drizzle-orm/singlestore-core';

const singlestoreTable = singlestoreTableCreator((name) => `project1_${name}`);

const users = singlestoreTable('users', {
  id: int('id').primaryKey(),
  name: text('name').notNull(),
});
```
```ts {10}
import { defineConfig } from "drizzle-kit";

export default defineConfig({
  schema: "./src/schema/*",
  out: "./drizzle",
  dialect: "singlestore", 
  dbCredentials: {
    url: process.env.DATABASE_URL,
  }
  tablesFilter: ["project1_*"],
});
```

You can apply multiple `or` filters:
```ts
tablesFilter: ["project1_*", "project2_*"]
```


## Printing SQL query
You can print SQL queries with `db` instance or by using **[`standalone query builder`](#standalone-query-builder)**.
```typescript copy
const query = db
  .select({ id: users.id, name: users.name })
  .from(users)
  .groupBy(users.id)
  .toSQL();
// query:
{
  sql: 'select `id`, `name` from `users` group by `users`.`id`',
  params: [],
}
```

## Raw SQL 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 `parametrized` queries.

```typescript copy
import { ..., SingleStoreRawQueryResult } from "drizzle-orm/singlestore";

const statement = sql`select * from ${users} where ${users.id} = ${userId}`;
const res: SingleStoreRawQueryResult = await db.execute(statement);
```


## Standalone query builder
Drizzle ORM provides a standalone query builder that allows you to build queries
without creating a database instance and get generated SQL.
```typescript copy
import { QueryBuilder } from 'drizzle-orm/singlestore-core';

const qb = new QueryBuilder();

const query = qb.select().from(users).where(eq(users.name, 'Dan'));
const { sql, params } = query.toSQL();
```

## Get typed columns
You can get a typed columns map,
very useful when you need to omit certain columns upon selection.

<Callout type='warning'>
`getColumns` available starting from `drizzle-orm@1.0.0-beta.2`(read more [here](/docs/singlestore/upgrade-v1))

If you are on pre-1 version(like `0.45.1`) then use `getTableColumns`
</Callout>


<br/>

<CodeTabs items={["index.ts", "schema.ts"]}>
  ```ts
  import { getColumns } from "drizzle-orm";
  import { user } from "./schema";

  const { password, role, ...rest } = getColumns(user);

  await db.select({ ...rest }).from(users);
  ```
  ```ts
  import { int, text, singlestoreTable } from "drizzle-orm/singlestore-core";

  export const user = singlestoreTable("user", {
    id: int("id").primaryKey().autoincrement(),
    name: text("name"),
    email: text("email"),
    password: text("password"),
    role: text("role").$type<"admin" | "customer">(),
  });
  ```
</CodeTabs>

## Get table information
```ts copy
import { getTableConfig, singlestoreTable } from 'drizzle-orm/singlestore-core';

export const table = singlestoreTable(...);

const {
  columns,
  indexes,
  checks,
  primaryKeys,
  name,
  schema,
} = getTableConfig(table);
```

## Compare objects types (instanceof alternative)

You can check if an object is of a specific Drizzle type using the `is()` function. 
You can use it with any available type in Drizzle.

<Callout type="warning" emoji="⭐️">
  You should always use `is()` instead of `instanceof`
</Callout>

**Few examples**
```ts
import { Column, is } from 'drizzle-orm';

if (is(value, Column)) {
  // value's type is narrowed to Column
}
```

### Mock Driver
This API is a successor to an undefined `drizzle({} as any)` API which we've used internally in Drizzle tests and rarely recommended to external developers. 

We decided to build and expose a proper API, every `drizzle` driver now has `drizzle.mock()`:
```ts
import { drizzle } from "drizzle-orm/...";

const db = drizzle.mock();
```

you can provide schema if necessary for types
```ts
import { drizzle } from "drizzle-orm/...";
import * as schema from "./schema"

const db = drizzle.mock({ schema });
```


Source: https://orm.drizzle.team/docs/singlestore/guides/count-rows

import Section from "@mdx/Section.astro";
import Prerequisites from "@mdx/Prerequisites.astro";
import CodeTabs from '@mdx/CodeTabs.astro';
import CodeTab from '@mdx/CodeTab.astro';
import Callout from '@mdx/Callout.astro';

<Prerequisites>
- Get started with [SingleStore](/docs/singlestore/get-started-singlestore)
- [Select statement](/docs/singlestore/select)
- [Filters](/docs/singlestore/operators) and [sql operator](/docs/singlestore/sql)
- [Aggregations](/docs/singlestore/select#aggregations) and [Aggregation helpers](/docs/singlestore/select#aggregations-helpers)
- [Joins](/docs/singlestore/joins)
</Prerequisites>

To count all rows in table you can use `count()` function or `sql` operator like below:

<CodeTabs items={["index.ts", "schema.ts"]}>
  <CodeTab>
    ```ts copy {6,9}
    import { count, sql } from 'drizzle-orm';
    import { products } from './schema';

    const db = drizzle(...);

    await db.select({ count: count() }).from(products);

    // Under the hood, the count() function casts its result to a number at runtime.
    await db.select({ count: sql`count(*)`.mapWith(Number) }).from(products);
    ```

    ```ts
    // result type
    type Result = {
      count: number;
    }[];
    ```

    ```sql
    select count(*) from products;
    ```
  </CodeTab>
  ```ts
  import { int, singlestoreTable, varchar } from 'drizzle-orm/singlestore-core';

  export const products = singlestoreTable('products', {
    id: int('id').primaryKey().autoincrement(),
    name: varchar('name', { length: 255 }).notNull(),
    discount: int('discount'),
    price: int('price').notNull(),
  });
  ```
</CodeTabs>

To count rows where the specified column contains non-NULL values you can use `count()` function with a column:

<Section>
```ts copy {1}
await db.select({ count: count(products.discount) }).from(products);
```

```ts
// result type
type Result = {
  count: number;
}[];
```

```sql
select count(`discount`) from products;
```
</Section>

Drizzle has simple and flexible API, which lets you create your custom solutions. In SingleStore, `count()` can be returned as a string by the driver, so cast it to a number when you need a numeric result:

<Section>
```ts copy {5,7,11,12}
import { AnyColumn, sql } from 'drizzle-orm';

const customCount = (column?: AnyColumn) => {
  if (column) {
    return sql<number>`cast(count(${column}) as unsigned)`; // In SingleStore cast to unsigned integer
  } else {
    return sql<number>`cast(count(*) as unsigned)`; // In SingleStore cast to unsigned integer
  }
};

await db.select({ count: customCount() }).from(products);
await db.select({ count: customCount(products.discount) }).from(products);
```

```sql
select cast(count(*) as unsigned) from products;
select cast(count(`discount`) as unsigned) from products;
```
</Section>


<Callout type="warning">
By specifying `sql<number>`, you are telling Drizzle that the **expected** type of the field is `number`.<br />
If you specify it incorrectly (e.g. use `sql<string>` for a field that will be returned as a number), the runtime value won't match the expected type.
Drizzle cannot perform any type casts based on the provided type generic, because that information is not available at runtime.

If you need to apply runtime transformations to the returned value, you can use the [`.mapWith()`](/docs/singlestore/sql#sqlmapwith) method.
</Callout>

To count rows that match a condition you can use `.where()` method:

<Section>
```ts copy {4,6}
import { count, gt } from 'drizzle-orm';

await db
  .select({ count: count() })
  .from(products)
  .where(gt(products.price, 100));
```

```sql
select count(*) from products where price > 100
```
</Section>

This is how you can use `count()` function with joins and aggregations:

<CodeTabs items={["index.ts", "schema.ts"]}>
	<CodeTab>
    ```ts copy {8,11,12,13}
    import { count, eq } from 'drizzle-orm';
    import { countries, cities } from './schema';

    // Count cities in each country
    await db
      .select({
        country: countries.name,
        citiesCount: count(cities.id),
      })
      .from(countries)
      .leftJoin(cities, eq(countries.id, cities.countryId))
      .groupBy(countries.id)
      .orderBy(countries.name);
    ```

    ```sql
    select countries.name, count(`cities`.`id`) from countries
      left join cities on countries.id = cities.country_id
      group by countries.id
      order by countries.name;
    ```
  </CodeTab>
  ```ts
  import { int, singlestoreTable, varchar } from 'drizzle-orm/singlestore-core';

  export const countries = singlestoreTable('countries', {
    id: int('id').primaryKey().autoincrement(),
    name: varchar('name', { length: 255 }).notNull(),
  });

  export const cities = singlestoreTable('cities', {
    id: int('id').primaryKey().autoincrement(),
    name: varchar('name', { length: 255 }).notNull(),
    countryId: int('country_id').notNull().references(() => countries.id),
  });
  ```
</CodeTabs>


Source: https://orm.drizzle.team/docs/singlestore/indexes-constraints

import Callout from '@mdx/Callout.astro';
import Section from '@mdx/Section.astro';

# Indexes & Constraints

## Constraints

SQL constraints are the rules enforced on table columns. They are used to prevent invalid data from being entered into the database.

This ensures the accuracy and reliability of your data in the database.

### Default

The `DEFAULT` clause specifies a default value to use for the column if no value provided by the user when doing an `INSERT`.
If there is no explicit `DEFAULT` clause attached to a column definition,
then the default value of the column is `NULL`.

An explicit `DEFAULT` clause may specify that the default value is `NULL`,
a string constant, a blob constant, a signed-number, or any constant expression enclosed in parentheses.

<Section>
    ```typescript
    import { sql } from "drizzle-orm";
    import { int, time, singlestoreTable } from "drizzle-orm/singlestore-core";
    
    const table = singlestoreTable("table", {
      int: int("int").default(42),
      time: time("time").default(sql`cast("14:06:10" AS TIME)`),
    });
    ```
    ```sql
    CREATE TABLE `table` (
      `int` int DEFAULT 42,
      `time` time DEFAULT cast("14:06:10" AS TIME)
    );
    ```
    </Section>

### Not null

By default, a column can hold **NULL** values. The `NOT NULL` constraint enforces a column to **NOT** accept **NULL** values.  

This enforces a field to always contain a value, which means that you cannot insert a new record,
or update a record without adding a value to this field.

<Section>
      ```typescript
      import { int, singlestoreTable } from "drizzle-orm/singlestore-core";

      const table = singlestoreTable('table', {
        int: int('int').notNull(),
      });
      ```

      ```sql
      CREATE TABLE `table` (
        `int` int NOT NULL
      );
      ```
    </Section>

### Unique

The `UNIQUE` constraint ensures that all values in a column are different.  

Both the `UNIQUE` and `PRIMARY KEY` constraints provide a guarantee for uniqueness for a column or set of columns.

A `PRIMARY KEY` constraint automatically has a `UNIQUE` constraint.  

<Callout type="info" emoji="ℹ️">
  You can have many `UNIQUE` constraints per table, but only one `PRIMARY KEY` constraint per table.
</Callout>

<Section>
      ```typescript
      import { int, varchar, unique, singlestoreTable } from "drizzle-orm/singlestore-core";

      export const user = singlestoreTable('user', {
        id: int('id').unique(),
      });

      export const table = singlestoreTable('table', {
        id: int('id').unique('custom_name'),
      });

      export const composite = singlestoreTable('composite_example', {
        id: int('id'),
        name: varchar('name', { length: 256 }),
      }, (t) => [
        unique().on(t.id, t.name),
        unique('custom_name').on(t.id, t.name)
      ]);
      ```

      ```sql
      CREATE TABLE `user` (
      	`id` int,
      	CONSTRAINT `user_id_unique` UNIQUE(`id`)
      );

      CREATE TABLE `table` (
      	`id` int,
      	CONSTRAINT `custom_name` UNIQUE(`id`)
      );

      CREATE TABLE `composite_example` (
        `id` int,
        `name` varchar(256),
        CONSTRAINT `composite_example_id_name_unique` UNIQUE(`id`,`name`),
        CONSTRAINT `custom_name` UNIQUE(`id`,`name`)
      );
      ```
    </Section>

### Primary Key

The `PRIMARY KEY` constraint uniquely identifies each record in a table.  
Primary keys must contain `UNIQUE` values, and cannot contain `NULL` values.  

A table can have only **ONE** primary key; and in the table, this primary key can consist of single or multiple columns (fields).

<Section>
      ```typescript
      import { int, text, singlestoreTable } from "drizzle-orm/singlestore-core";

      export const user = singlestoreTable("user", {
        id: int("id").autoincrement().primaryKey(),
      })

      export const table = singlestoreTable("table", {
        cuid: text("cuid").primaryKey(),
      })
      ```

      ```sql
      CREATE TABLE `user` (
        `id` int AUTO_INCREMENT PRIMARY KEY NOT NULL
      );

      CREATE TABLE `table` (
        `cuid` text PRIMARY KEY NOT NULL
      );
      ```
    </Section>

### Composite Primary Key

Just like `PRIMARY KEY`, composite primary key uniquely identifies each record in a table using multiple fields.

Drizzle ORM provides a standalone `primaryKey` operator for that:

<Section>
      ```typescript {18, 19}
      import { int, text, primaryKey, singlestoreTable } from "drizzle-orm/singlestore-core";

      export const user = singlestoreTable("user", {
        id: int("id").autoincrement().primaryKey(),
        name: text("name"),
      });

      export const book = singlestoreTable("book", {
        id: int("id").autoincrement().primaryKey(),
        name: text("name"),
      });

      export const booksToAuthors = singlestoreTable("books_to_authors", {
        authorId: int("author_id"),
        bookId: int("book_id"),
      }, (table) => [
        primaryKey({ columns: [table.bookId, table.authorId] }),
        // Or PK with custom name
        primaryKey({ name: 'custom_name', columns: [table.bookId, table.authorId] }),
      ]);
      ```

      ```sql {6}
      ...

      CREATE TABLE `books_to_authors` (
        `author_id` int,
        `book_id` int,
        PRIMARY KEY(`book_id`,`author_id`)
      );
      ```
    </Section>

## Indexes

Drizzle ORM provides API for both `index` and `unique index` declaration:

<Section>
    ```typescript copy {9-10}
    import { int, text, index, uniqueIndex, singlestoreTable } from "drizzle-orm/singlestore-core";

    export const user = singlestoreTable("user", {
      id: int("id").primaryKey().autoincrement(),
      name: text("name"),
      email: text("email"),
    }, (table) => [
      index("name_idx").on(table.name),
      uniqueIndex("email_idx").on(table.email),
    ]);
    ```
    ```sql {5-6}
    CREATE TABLE `user` (
      ...
    );

    CREATE INDEX `name_idx` ON `user` (`name`);
    CREATE UNIQUE INDEX `email_idx` ON `user` (`email`);
    ```
    </Section>


Source: https://orm.drizzle.team/docs/singlestore/insert

import Section from '@mdx/Section.astro';
import Callout from '@mdx/Callout.astro';
import Tab from '@mdx/Tab.astro';
import Tabs from '@mdx/Tabs.astro';

# SQL Insert
Drizzle ORM provides you the most SQL-like way to insert rows into the database tables.

Inserting data with Drizzle is extremely straightforward and sql-like. See for yourself:

<Section>
```typescript copy 
await db.insert(users).values({ name: 'Andrew' });
```
```sql
insert into `users` (`name`) values ('Andrew');
```
</Section>

If you need insert type for a particular table you can use `typeof usersTable.$inferInsert` syntax. 
```typescript copy 
type NewUser = typeof users.$inferInsert;

const insertUser = async (user: NewUser) => {
  return db.insert(users).values(user);
}

const newUser: NewUser = { name: "Alef" };
await insertUser(newUser);
```

## $returningId
SingleStore doesn't have native support for `RETURNING` after using `INSERT`. There is only one way to do it for `primary keys` with `autoincrement` (or `serial`) types, where you can access `insertId` and `affectedRows` fields. We've prepared an automatic way for you to handle such cases with Drizzle and automatically receive all inserted IDs as separate objects

```ts
import { boolean, int, text, singlestoreTable } from 'drizzle-orm/singlestore-core';

const usersTable = singlestoreTable('users', {
  id: int('id').primaryKey(),
  name: text('name').notNull(),
  verified: boolean('verified').notNull().default(false),
});


const result = await db.insert(usersTable).values([{ name: 'John' }, { name: 'John1' }]).$returningId();
//    ^? { id: number }[]
```

Also with Drizzle, you can specify a `primary key` with `$default` function that will generate custom primary keys at runtime. We will also return those generated keys for you in the `$returningId()` call

```ts
import { varchar, text, singlestoreTable } from 'drizzle-orm/singlestore-core';
import { createId } from '@paralleldrive/cuid2';

const usersTableDefFn = singlestoreTable('users_default_fn', {
  customId: varchar('id', { length: 256 }).primaryKey().$defaultFn(createId),
  name: text('name').notNull(),
});


const result = await db.insert(usersTableDefFn).values([{ name: 'John' }, { name: 'John1' }]).$returningId();
//  ^? { customId: string }[]
```

> If there is no primary keys -> type will be `{}[]` for such queries

## Insert multiple rows
```typescript copy
await db.insert(users).values([{ name: 'Andrew' }, { name: 'Dan' }]);
```

## Upserts and conflicts
Drizzle ORM provides simple interfaces for handling upserts and conflicts.

### On duplicate key update
SingleStore supports [`ON DUPLICATE KEY UPDATE`](https://dev.mysql.com/doc/refman/8.0/en/insert-on-duplicate.html) instead of `ON CONFLICT` clauses. SingleStore will automatically determine the conflict target based on the primary key and unique indexes, and will update the row if *any* unique index conflicts.

Drizzle supports this through the `onDuplicateKeyUpdate` method:

```typescript
// Note that SingleStore automatically determines targets based on the primary key and unique indexes
await db.insert(users)
  .values({ id: 1, name: 'John' })
  .onDuplicateKeyUpdate({ set: { name: 'John' } });
```

While SingleStore does not directly support doing nothing on conflict, you can perform a no-op by setting any column's value to itself and achieve the same effect:

```typescript
import { sql } from 'drizzle-orm';

await db.insert(users)
  .values({ id: 1, name: 'John' })
  .onDuplicateKeyUpdate({ set: { id: sql`id` } });
```

## Insert into ... select

As the SingleStore documentation follows MySQL-compatible `INSERT ... SELECT` behavior:

<Callout>
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
</Callout>

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


<Tabs items={["Query Builder", "Callback", "SQL template tag"]}>
<Tab>
<Section>
```ts
const insertedEmployees = await db
  .insert(employees)
  .select(
    db.select({ name: users.name }).from(users).where(eq(users.role, 'employee'))
  );
```
```ts
const qb = new QueryBuilder();
await db.insert(employees).select(
    qb.select({ name: users.name }).from(users).where(eq(users.role, 'employee'))
);
```
</Section>
</Tab>
<Tab>
<Section>
```ts
await db.insert(employees).select(
    () => db.select({ name: users.name }).from(users).where(eq(users.role, 'employee'))
);
```
```ts
await db.insert(employees).select(
    (qb) => qb.select({ name: users.name }).from(users).where(eq(users.role, 'employee'))
);
```
</Section>
</Tab>
<Tab>
<Section>
```ts
await db.insert(employees).select(
    sql`select users.name as name from users where users.role = 'employee'`
);
```
```ts
await db.insert(employees).select(
    () => sql`select users.name as name from users where users.role = 'employee'`
);
```
</Section>
</Tab>
</Tabs>


Source: https://orm.drizzle.team/docs/singlestore/joins

import CodeTabs from '@mdx/CodeTabs.astro';
import CodeTab from '@mdx/CodeTab.astro';
import Section from '@mdx/Section.astro';

# Joins [SQL]
Join clause in SQL is used to combine 2 or more tables, based on related columns between them.
Drizzle ORM joins syntax is a balance between the SQL-likeness and type safety.

## Join types
Drizzle ORM has APIs for `INNER JOIN`, `LEFT JOIN`, `RIGHT JOIN`, and `CROSS JOIN`.
Lets have a quick look at examples based on below table schemas:
```typescript copy
export const users = singlestoreTable('users', {
  id: int('id').primaryKey().autoincrement(),
  name: varchar('name', { length: 255 }).notNull(),
});

export const pets = singlestoreTable('pets', {
  id: int('id').primaryKey().autoincrement(),
  name: varchar('name', { length: 255 }).notNull(),
  ownerId: int('owner_id').notNull().references(() => users.id),
})
```

### Left Join
<Section>
```typescript copy
const result = await db.select().from(users).leftJoin(pets, eq(users.id, pets.ownerId))
```
```sql
select ... from `users` left join `pets` on `users`.`id` = `pets`.`owner_id`
```
```typescript
// result type
const result: {
    user: {
        id: number;
        name: string;
    };
    pets: {
        id: number;
        name: string;
        ownerId: number;
    } | null;
}[];
```
</Section>


### Right Join
<Section>
```typescript copy
const result = await db.select().from(users).rightJoin(pets, eq(users.id, pets.ownerId))
```
```sql
select ... from `users` right join `pets` on `users`.`id` = `pets`.`owner_id`
```
```typescript
// result type
const result: {
    user: {
        id: number;
        name: string;
    } | null;
    pets: {
        id: number;
        name: string;
        ownerId: number;
    };
}[];
```
</Section>

### Inner Join
<Section>
```typescript copy
const result = await db.select().from(users).innerJoin(pets, eq(users.id, pets.ownerId))
```
```sql
select ... from `users` inner join `pets` on `users`.`id` = `pets`.`owner_id`
```
```typescript
// result type
const result: {
    user: {
        id: number;
        name: string;
    };
    pets: {
        id: number;
        name: string;
        ownerId: number;
    };
}[];
```
</Section>



### Cross Join
<Section>
```typescript copy
const result = await db.select().from(users).crossJoin(pets)
```
```sql
select ... from `users` cross join `pets`
```
```typescript
// result type
const result: {
    user: {
        id: number;
        name: string;
    };
    pets: {
        id: number;
        name: string;
        ownerId: number;
    };
}[];
```
</Section>


## Partial select
If you need to select a particular subset of fields or to have a flat response type, Drizzle ORM
supports joins with partial select and will automatically infer return type based on `.select({ ... })` structure.
<Section>
```typescript copy
await db.select({
  userId: users.id,
  petId: pets.id,
}).from(user).leftJoin(pets, eq(users.id, pets.ownerId))
```
```sql
select `users`.`id`, `pets`.`id` from `users` left join `pets` on `users`.`id` = `pets`.`owner_id`
```
```typescript
// result type
const result: {
  userId: number;
  petId: number | null;
}[];
```
</Section>
You might've noticed that `petId` can be null now, it's because we're left joining and there can be users without a pet.

It's very important to keep in mind when using `sql` operator for partial selection fields and aggregations when needed,
you should to use `sql<type | null>` for proper result type inference, that one is on you!
<Section>
```typescript copy
const result = await db.select({
  userId: users.id,
  petId: pets.id,
  petName1: sql`upper(${pets.name})`,
  petName2: sql<string | null>`upper(${pets.name})`,
  //˄we should explicitly tell 'string | null' in type, since we're left joining that field
}).from(user).leftJoin(pets, eq(users.id, pets.ownerId))
```
```sql
select `users`.`id`, `pets`.`id`, upper(`pets`.`name`)... from `users` left join `pets` on `users`.`id` = `pets`.`owner_id`
```
```typescript
// result type
const result: {
  userId: number;
  petId: number | null;
  petName1: unknown;
  petName2: string | null;
}[];
```
</Section>
To avoid plethora of nullable fields when joining tables with lots of columns we can utilise our **nested select object syntax**,
our smart type inference will make whole object nullable instead of making all table fields nullable!
<Section>
```typescript copy
await db.select({
  userId: users.id,
  userName: users.name,
  pet: {
    id: pets.id,
    name: pets.name,
    upperName: sql<string>`upper(${pets.name})`
  }
}).from(user).leftJoin(pets, eq(users.id, pets.ownerId))
```
```sql
select ... from `users` left join `pets` on `users`.`id` = `pets`.`owner_id`
```
```typescript
// result type
const result: {
    userId: number;
    userName: string;
    pet: {
        id: number;
        name: string;
        upperName: string;
    } | null;
}[];
```
</Section>

## Aliases & Selfjoins
Drizzle ORM supports table aliases which comes really handy when you need to do selfjoins.

Lets say you need to fetch users with their parents:
<CodeTabs items={["index.ts", "schema.ts"]}>
<CodeTab>
```typescript copy
import { user } from "./schema";

const parent = alias(user, "parent");
const result = db
  .select()
  .from(user)
  .leftJoin(parent, eq(parent.id, user.parentId));
```
```sql
select ... from `user` left join `user` `parent` on `parent`.`id` = `user`.`parent_id`
```
```typescript
// result type
const result: {
    user: {
        id: number;
        name: string;
        parentId: number;
    };
    parent: {
        id: number;
        name: string;
        parentId: number;
    } | null;
}[];
```
</CodeTab>

```typescript
export const user = singlestoreTable("user", {
  id: int("id").primaryKey().autoincrement(),
  name: varchar("name", { length: 255 }).notNull(),
  parentId: int("parent_id").notNull().references((): AnyColumn => user.id)
});
```

</CodeTabs>

## Aggregating results
Drizzle ORM delivers name-mapped results from the driver without changing the structure.

You're free to operate with results the way you want, here's an example of mapping many-one relational data:
```typescript
type User = typeof users.$inferSelect;
type Pet = typeof pets.$inferSelect;

const rows = db.select({
    user: users,
    pet: pets,
  }).from(users).leftJoin(pets, eq(users.id, pets.ownerId)).all();

const result = rows.reduce<Record<number, { user: User; pets: Pet[] }>>(
  (acc, row) => {
    const user = row.user;
    const pet = row.pet;

    if (!acc[user.id]) {
      acc[user.id] = { user, pets: [] };
    }

    if (pet) {
      acc[user.id].pets.push(pet);
    }

    return acc;
  },
  {}
);

// result type
const result: Record<number, {
    user: User;
    pets: Pet[];
}>;
```

## Many-to-one example
```typescript
import { singlestoreTable, text, integer } from 'drizzle-orm/singlestore-core';
import { drizzle } from 'drizzle-orm/singlestore';

const cities = singlestoreTable('cities', {
  id: int('id').primaryKey().autoincrement(),
  name: varchar('name', { length: 255 }),
});

const users = singlestoreTable('users', {
  id: int('id').primaryKey().autoincrement(),
  name: varchar('name', { length: 255 }),
  cityId: int('city_id').references(() => cities.id)
});

const db = drizzle();

const result = db.select().from(cities).leftJoin(users, eq(cities.id, users.cityId)).all();
```
## Many-to-many example
```typescript
const users = singlestoreTable('users', {
  id: int('id').primaryKey().autoincrement(),
  name: varchar('name', { length: 255 }),
});

const chatGroups = singlestoreTable('chat_groups', {
  id: int('id').primaryKey().autoincrement(),
  name: varchar('name', { length: 255 }),
});

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


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


Source: https://orm.drizzle.team/docs/singlestore/kit-custom-migrations

import CodeTab from '@mdx/CodeTab.astro';
import CodeTabs from '@mdx/CodeTabs.astro';
import Section from '@mdx/Section.astro';
import Tab from '@mdx/Tab.astro';
import Tabs from '@mdx/Tabs.astro';
import Callout from '@mdx/Callout.astro';
import Npm from '@mdx/Npm.astro';
import Npx from '@mdx/Npx.astro';
import Steps from '@mdx/Steps.astro';
import Prerequisites from "@mdx/Prerequisites.astro"

# Migrations with Drizzle Kit
<Prerequisites>
- Get started with Drizzle and `drizzle-kit` - [read here](/docs/get-started)
- Drizzle schema fundamentals - [read here](/docs/sql-schema-declaration)
- Database connection basics - [read here](/docs/connect-overview)
- Drizzle migrations fundamentals - [read here](/docs/migrations)
- Drizzle Kit [overview](/docs/kit-overview) and [config file](/docs/drizzle-config-file)
- `drizzle-kit generate` command - [read here](/docs/drizzle-kit-generate)
- `drizzle-kit migrate` command - [read here](/docs/drizzle-kit-migrate)
</Prerequisites>

Drizzle lets you generate empty migration files to write your own custom SQL migrations 
for DDL alternations currently not supported by Drizzle Kit or data seeding, which you can then run with [`drizzle-kit migrate`](/docs/drizzle-kit-migrate) command.

```shell
drizzle-kit generate --custom --name=seed-users
```
<Section>
```plaintext {4}
📦 <project root>
 ├ 📂 drizzle
 │ ├ 📂 20242409125510_init_sql
 │ └ 📂 20242409135510_seed-users
 ├ 📂 src
 └ …
```
```sql
-- ./drizzle/20242409135510_seed-users.sql

INSERT INTO "users" ("name") VALUES('Dan');
INSERT INTO "users" ("name") VALUES('Andrew');
INSERT INTO "users" ("name") VALUES('Dandrew');
```
</Section>

### Running JavaScript and TypeScript migrations
We will add ability to run custom JavaScript and TypeScript migration/seeding scripts in the upcoming release, you can follow [github discussion](https://github.com/drizzle-team/drizzle-orm/discussions/2832).

Source: https://orm.drizzle.team/docs/singlestore/kit-overview

import CodeTab from '@mdx/CodeTab.astro';
import CodeTabs from '@mdx/CodeTabs.astro';
import Section from '@mdx/Section.astro';
import Tab from '@mdx/Tab.astro';
import Tabs from '@mdx/Tabs.astro';
import Callout from '@mdx/Callout.astro';
import Npm from '@mdx/Npm.astro';
import Npx from '@mdx/Npx.astro';
import Steps from '@mdx/Steps.astro';
import Prerequisites from "@mdx/Prerequisites.astro"

# Migrations with Drizzle Kit
<Prerequisites>
- Get started with Drizzle and `drizzle-kit` - [read here](/docs/singlestore/get-started)
- Drizzle schema fundamentals - [read here](/docs/singlestore/sql-schema-declaration)
- Database connection basics - [read here](/docs/singlestore/connect-overview)
- Drizzle migrations fundamentals - [read here](/docs/singlestore/migrations)
</Prerequisites>


**Drizzle Kit** is a CLI tool for managing SQL database migrations with Drizzle.
<Npm>
  -D drizzle-kit
</Npm>
<Callout type="warning">
Make sure to first go through Drizzle [get started](/docs/singlestore/get-started) and [migration fundamentals](/docs/singlestore/migrations) and pick SQL migration flow that suits your business needs best. 
</Callout>

Based on your schema, Drizzle Kit let's you generate and run SQL migration files, 
push schema directly to the database, pull schema from database, spin up drizzle studio and has a couple of utility commands.
<Npx>
drizzle-kit generate
drizzle-kit migrate
drizzle-kit push
drizzle-kit pull
drizzle-kit check
drizzle-kit up
drizzle-kit studio
</Npx>


|                                                      |                                                                                                                                                                    |
| :--------------------------------------------------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| [`drizzle-kit generate`](/docs/singlestore/drizzle-kit-generate) | lets you generate SQL migration files based on your Drizzle schema either upon declaration or on subsequent changes, [see here](/docs/singlestore/drizzle-kit-generate).       |
| [`drizzle-kit migrate`](/docs/singlestore/drizzle-kit-migrate)   | lets you apply generated SQL migration files to your database, [see here](/docs/singlestore/drizzle-kit-migrate).                                                              |
| [`drizzle-kit pull`](/docs/singlestore/drizzle-kit-pull)         | lets you pull(introspect) database schema, convert it to Drizzle schema and save it to your codebase, [see here](/docs/singlestore/drizzle-kit-pull)                           |
| [`drizzle-kit push`](/docs/singlestore/drizzle-kit-push)         | lets you push your Drizzle schema to database either upon declaration or on subsequent schema changes, [see here](/docs/singlestore/drizzle-kit-push)                          |
| [`drizzle-kit studio`](/docs/singlestore/drizzle-kit-studio)     | will connect to your database and spin up proxy server for Drizzle Studio which you can use for convenient database browsing, [see here](/docs/singlestore/drizzle-kit-studio) |
| [`drizzle-kit check`](/docs/singlestore/drizzle-kit-check)       | will walk through all generate migrations and check for any race conditions(collisions) of generated migrations, [see here](/docs/singlestore/drizzle-kit-check)               |
| [`drizzle-kit up`](/docs/singlestore/drizzle-kit-up)             | used to upgrade snapshots of previously generated migrations, [see here](/docs/singlestore/drizzle-kit-up)                                                                     |
<br/>

Drizzle Kit is configured through [drizzle.config.ts](/docs/singlestore/drizzle-config-file) configuration file or via CLI params.<br/>
It's required to at least provide SQL `dialect` and `schema` path for Drizzle Kit to know how to generate migrations.
```
📦 <project root>
 ├ 📂 drizzle
 ├ 📂 src
 ├ 📜 .env
 ├ 📜 drizzle.config.ts  <--- Drizzle config file
 ├ 📜 package.json
 └ 📜 tsconfig.json
```

<CodeTabs items={["simple config", "extended config"]}>
```ts
import { defineConfig } from "drizzle-kit";

export default defineConfig({
  dialect: "singlestore",
  schema: "./src/schema.ts",
});
```
```ts
import { defineConfig } from "drizzle-kit";

export default defineConfig({
  out: "./drizzle",
  dialect: "singlestore",
  schema: "./src/schema.ts",

  driver: "pglite",
  dbCredentials: {
    url: "./database/",
  },

  extensionsFilters: ["postgis"],
  schemaFilter: "public",
  tablesFilter: "*",

  introspect: {
    casing: "camel",
  },

  migrations: {
    prefix: "timestamp",
    table: "__drizzle_migrations__",
    schema: "public",
  },

  breakpoints: true,
  strict: true,
  verbose: true,
});
```
</CodeTabs>

You can provide Drizzle Kit config path via CLI param, it's very useful when you have multiple database stages or multiple databases or different databases on the same project:

<Npx>
  drizzle-kit push --config=drizzle-dev.drizzle.config
  drizzle-kit push --config=drizzle-prod.drizzle.config
</Npx>
```plaintext {5-6}
📦 <project root>
 ├ 📂 drizzle
 ├ 📂 src
 ├ 📜 .env
 ├ 📜 drizzle-dev.config.ts
 ├ 📜 drizzle-prod.config.ts
 ├ 📜 package.json
 └ 📜 tsconfig.json
```


Source: https://orm.drizzle.team/docs/singlestore/migrations

export const a = 10;

import Callout from '@mdx/Callout.astro';
import Steps from '@mdx/Steps.astro';
import CodeTab from '@mdx/CodeTab.astro';
import CodeTabs from '@mdx/CodeTabs.astro';
import Section from '@mdx/Section.astro';
import Tab from '@mdx/Tab.astro';
import Tabs from '@mdx/Tabs.astro';
import Npm from '@mdx/Npm.astro';
import Tag from '@mdx/Tag.astro'


# Drizzle migrations fundamentals

SQL databases require you to specify a **strict schema** of entities you're going to store upfront 
and if (when) you need to change the shape of those entities - you will need to do it via **schema migrations**.

There're multiple production grade ways of managing database migrations. 
Drizzle is designed to perfectly suits all of them, regardless of you going **database first** or **codebase first**.

**Database first** is when your database schema is a source of truth. You manage your database schema either directly on the database or 
via database migration tools and then you pull your database schema to your codebase application level entities.  
 
**Codebase first** is when database schema in your codebase is a source of truth and is under version control. You declare and manage your database schema in JavaScript/TypeScript
and then you apply that schema to the database itself either with Drizzle, directly or via external migration tools. 

#### How can Drizzle help?
We've built [**drizzle-kit**](/docs/singlestore/kit-overview) - CLI app for managing migrations with Drizzle. 
```shell
drizzle-kit migrate
drizzle-kit generate
drizzle-kit push
drizzle-kit pull
```
It is designed to let you choose how to approach migrations based on your current business demands. 

It fits in both database and codebase first approaches, it lets you **push your schema** or **generate SQL migration** files or **pull the schema** from database. 
It is perfect wether you work alone or in a team.
<br/>

<hr/>
<rem/>

**Now let's pick the best option for your project:**
<rem/>

<Tag style="font-size: 12px">**Option 1**</Tag>
> I manage database schema myself using external migration tools or by running SQL migrations directly on my database.
> From Drizzle I just need to get current state of the schema from my database and save it as TypeScript schema file.

<Callout collapsed="Expand details">
That's a **database first** approach. You have your database schema as a **source of truth** and 
Drizzle lets you pull database schema to TypeScript using [`drizzle-kit pull`](/docs/singlestore/drizzle-kit-pull) command.

<Section>
```
                                  ┌────────────────────────┐      ┌─────────────────────────┐ 
                                  │                        │ <---  CREATE TABLE "users" (
┌──────────────────────────┐      │                        │        `id` int auto_increment primary key,
│ ~ drizzle-kit pull       │      │                        │        `name` varchar(255),
└─┬────────────────────────┘      │        DATABASE        │        `email` varchar(255) unique
  │                               │                        │       );
  └ Pull datatabase schema -----> │                        │
  ┌ Generate Drizzle       <----- │                        │
  │ schema TypeScript file        └────────────────────────┘
  │
  v
```
```typescript
import * as p from "drizzle-orm/singlestore-core";

export const users = p.singlestoreTable("users", {
  id: p.int().primaryKey().autoincrement(),
  name: p.varchar({ length: 255 }),
  email: p.varchar({ length: 255 }).unique(),
});
```
</Section>
</Callout>

<rem/>
<rem/>
<rem/>

<Tag style="font-size: 12px">**Option 2**</Tag>
> I want to have database schema in my TypeScript codebase, 
> I don't wanna deal with SQL migration files.  
> I want Drizzle to "push" my schema directly to the database

<Callout collapsed="Expand details">
That's a **codebase first** approach. You have your TypeScript Drizzle schema as a **source of truth** and 
Drizzle lets you push schema changes to the database using [`drizzle-kit push`](/docs/singlestore/drizzle-kit-push) command.

That's the best approach for rapid prototyping and we've seen dozens of teams 
and solo developers successfully using it as a primary migrations flow in their production applications.

<Section>
```typescript {6} filename="src/schema.ts"
import * as p from "drizzle-orm/singlestore-core";

export const users = p.singlestoreTable("users", {
  id: p.int().primaryKey().autoincrement(),
  name: p.varchar({ length: 255 }),
  email: p.varchar({ length: 255 }).unique(), // <--- added column
});
```
```
Add column to `users` table                                                                          
┌──────────────────────────┐                  
│ + email: text().unique() │                  
└─┬────────────────────────┘                  
  │                                           
  v                                           
┌──────────────────────────┐                  
│ ~ drizzle-kit push       │                  
└─┬────────────────────────┘                  
  │                                           ┌──────────────────────────┐
  └ Pull current datatabase schema ---------> │                          │
                                              │                          │
  ┌ Generate alternations based on diff <---- │         DATABASE         │
  │                                           │                          │
  └ Apply migrations to the database -------> │                          │
                                       │      └──────────────────────────┘
                                       │
  ┌────────────────────────────────────┴──────────────┐
   ALTER TABLE `users` ADD COLUMN `email` varchar(255) unique; 
```
</Section>
</Callout>

<rem/>
<rem/>
<rem/>

<Tag style="font-size: 12px">**Option 3**</Tag>
> I want to have database schema in my TypeScript codebase, 
> I want Drizzle to generate SQL migration files for me and apply them to my database

<Callout collapsed="Expand details">
That's a **codebase first** approach. You have your TypeScript Drizzle schema as a source of truth and 
Drizzle lets you generate SQL migration files based on your schema changes with [`drizzle-kit generate`](/docs/singlestore/drizzle-kit-generate)
and then apply them to the database with [`drizzle-kit migrate`](/docs/singlestore/drizzle-kit-migrate) commands. 
<Section>
```typescript filename="src/schema.ts"
import * as p from "drizzle-orm/singlestore-core";

export const users = p.singlestoreTable("users", {
  id: p.int().primaryKey().autoincrement(),
  name: p.varchar({ length: 255 }),
  email: p.varchar({ length: 255 }).unique(),
});
```
```                                  
┌────────────────────────┐                  
│ $ drizzle-kit generate │                  
└─┬──────────────────────┘                  
  │                                           
  └ 1. read previous migration folders
    2. find diff between current and previous schema
    3. prompt developer for renames if necessary
  ┌ 4. generate SQL migration and persist to file
  │    ┌─┴───────────────────────────────────────┐  
  │      📂 drizzle       
  │      └ 📂 20242409125510_premium_mister_fear
  │        ├ 📜 snapshot.json
  │        └ 📜 migration.sql
  v
```
```sql
-- drizzle/20242409125510_premium_mister_fear/migration.sql

CREATE TABLE `users` (
 `id` int auto_increment primary key,
 `name` varchar(255),
 `email` varchar(255) unique
);
```
```
┌───────────────────────┐                  
│ $ drizzle-kit migrate │                  
└─┬─────────────────────┘                  
  │                                                         ┌──────────────────────────┐                                         
  └ 1. read migration.sql files in migrations folder        │                          │
    2. fetch migration history from database -------------> │                          │
  ┌ 3. pick previously unapplied migrations <-------------- │         DATABASE         │
  └ 4. apply new migration to the database ---------------> │                          │
                                                            │                          │
                                                            └──────────────────────────┘
[✓] done!                                                 
```
</Section>
</Callout>

<rem/>
<rem/>
<rem/>

<Tag style="font-size: 12px">**Option 4**</Tag>
> I want to have database schema in my TypeScript codebase,
> I want Drizzle to generate SQL migration files for me and I want Drizzle to apply them during runtime

<Callout collapsed="Expand details">
That's a **codebase first** approach. You have your TypeScript Drizzle schema as a source of truth and 
Drizzle lets you generate SQL migration files based on your schema changes with [`drizzle-kit generate`](/docs/singlestore/drizzle-kit-generate) and then 
you can apply them to the database during runtime of your application.

This approach is widely used for **monolithic** applications when you apply database migrations 
during zero downtime deployment and rollback DDL changes if something fails. 
This is also used in **serverless** deployments with migrations running in **custom resource** once during deployment process.

<Section>
```typescript filename="src/schema.ts"
import * as p from "drizzle-orm/singlestore-core";

export const users = p.singlestoreTable("users", {
  id: p.int().primaryKey().autoincrement(),
  name: p.varchar({ length: 255 }),
  email: p.varchar({ length: 255 }).unique(),
});
```
```                                  
┌────────────────────────┐                  
│ $ drizzle-kit generate │                  
└─┬──────────────────────┘                  
  │                                           
  └ 1. read previous migration folders
    2. find diff between current and previous schema
    3. prompt developer for renames if necessary
  ┌ 4. generate SQL migration and persist to file
  │    ┌─┴───────────────────────────────────────┐  
  │      📂 drizzle       
  │      └ 📂 20242409125510_premium_mister_fear
  │        ├ 📜 snapshot.json
  │        └ 📜 migration.sql
  v
```
```sql
-- drizzle/20242409125510_premium_mister_fear/migration.sql

CREATE TABLE `users` (
 `id` int auto_increment primary key,
 `name` varchar(255),
 `email` varchar(255) unique
);
```
```ts
// index.ts
import { drizzle } from "drizzle-orm/singlestore"
import { migrate } from 'drizzle-orm/singlestore/migrator';

const db = drizzle(process.env.DATABASE_URL);

await migrate(db);
```
```
┌───────────────────────┐                  
│ npx tsx src/index.ts  │                  
└─┬─────────────────────┘                  
  │                                                      
  ├ 1. init database connection                             ┌──────────────────────────┐                                         
  └ 2. read migration.sql files in migrations folder        │                          │
    3. fetch migration history from database -------------> │                          │
  ┌ 4. pick previously unapplied migrations <-------------- │         DATABASE         │
  └ 5. apply new migration to the database ---------------> │                          │
                                                            │                          │
                                                            └──────────────────────────┘
[✓] done!                                                 
```
</Section>
</Callout>

<rem/>
<rem/>
<rem/>

<Tag style="font-size: 12px">**Option 5**</Tag>
> I want to have database schema in my TypeScript codebase,
> I want Drizzle to generate SQL migration files for me,
> but I will apply them to my database myself or via external migration tools 

<Callout collapsed="Expand details">
That's a **codebase first** approach. You have your TypeScript Drizzle schema as a source of truth and 
Drizzle lets you generate SQL migration files based on your schema changes with [`drizzle-kit generate`](/docs/singlestore/drizzle-kit-generate) and then 
you can apply them to the database either directly or via external migration tools.

<Section>
```typescript filename="src/schema.ts"
import * as p from "drizzle-orm/singlestore-core";

export const users = p.singlestoreTable("users", {
  id: p.int().primaryKey().autoincrement(),
  name: p.varchar({ length: 255 }),
  email: p.varchar({ length: 255 }).unique(),
});
```
```                                  
┌────────────────────────┐                  
│ $ drizzle-kit generate │                  
└─┬──────────────────────┘                  
  │                                           
  └ 1. read previous migration folders
    2. find diff between current and previous scheama
    3. prompt developer for renames if necessary
  ┌ 4. generate SQL migration and persist to file
  │    ┌─┴───────────────────────────────────────┐  
  │      📂 drizzle       
  │      └ 📂 20242409125510_premium_mister_fear
  │        ├ 📜 snapshot.json
  │        └ 📜 migration.sql
  v
```
```sql
-- drizzle/20242409125510_premium_mister_fear/migration.sql

CREATE TABLE `users` (
 `id` int auto_increment primary key,
 `name` varchar(255),
 `email` varchar(255) unique
);
```
```
┌───────────────────────────────────┐                  
│ (._.) now you run your migrations │           
└─┬─────────────────────────────────┘  
  │
 directly to the database
  │                                         ┌────────────────────┐
  ├────────────────────────────────────┬───>│                    │  
  │                                    │    │      Database      │           
 or via external tools                 │    │                    │   
  │                                    │    └────────────────────┘
  │  ┌────────────────────┐            │      
  └──│ Bytebase           ├────────────┘         
     ├────────────────────┤  
     │ Liquibase          │
     ├────────────────────┤ 
     │ Atlas              │
     ├────────────────────┤ 
     │ etc…               │
     └────────────────────┘

[✓] done!                                                 
```
</Section>
</Callout>

<rem/>
<rem/>
<rem/>

<Tag style="font-size: 12px">**Option 6**</Tag>
> I want to have database schema in my TypeScript codebase,
> I want Drizzle to output the SQL representation of my Drizzle schema to the console,
> and I will apply them to my database via [Atlas](https://atlasgo.io/guides/orms/drizzle)

<Callout collapsed="Expand details">
That's a **codebase first** approach. You have your TypeScript Drizzle schema as a source of truth and 
Drizzle lets you export SQL statements based on your schema changes with [`drizzle-kit export`](/docs/singlestore/drizzle-kit-generate) and then 
you can apply them to the database via [Atlas](https://atlasgo.io/guides/orms/drizzle) or other external SQL migration tools.

<Section>
```typescript filename="src/schema.ts"
import * as p from "drizzle-orm/singlestore-core";

export const users = p.singlestoreTable("users", {
  id: p.int().primaryKey().autoincrement(),
  name: p.varchar({ length: 255 }),
  email: p.varchar({ length: 255 }).unique(),
});
```
```                                  
┌────────────────────────┐                  
│ $ drizzle-kit export   │                  
└─┬──────────────────────┘                  
  │                                           
  └ 1. read your drizzle schema
    2. generated SQL representation of your schema
  ┌ 3. outputs to console
  │    
  │        
  v
```
```sql
CREATE TABLE `users` (
 `id` int auto_increment primary key,
 `name` varchar(255),
 `email` varchar(255) unique
);
```
```
┌───────────────────────────────────┐                  
│ (._.) now you run your migrations │           
└─┬─────────────────────────────────┘  
  │
 via Atlas
  │                                    ┌──────────────┐
  │  ┌────────────────────┐            │              │
  └──│ Atlas              ├───────────>│  Database    │      
     └────────────────────┘            │              │       
                                       └──────────────┘

[✓] done!                                                 
```
</Section>
</Callout>

<rem/>
<rem/>


Source: https://orm.drizzle.team/docs/singlestore/operators

import Section from '@mdx/Section.astro';

# Filter and conditional operators
We natively support all dialect specific filter and conditional operators.

You can import all filter & conditional from `drizzle-orm`:
```typescript copy
import { eq, ne, gt, gte, ... } from "drizzle-orm";
```

### eq

  
Value equal to `n`
<Section>
```typescript copy
import { eq } from "drizzle-orm";

db.select().from(table).where(eq(table.column, 5));
```

```sql copy
SELECT * FROM table WHERE table.column = 5
```
</Section>

<Section>
```typescript
import { eq } from "drizzle-orm";

db.select().from(table).where(eq(table.column1, table.column2));
```

```sql
SELECT * FROM table WHERE table.column1 = table.column2
```
</Section>

### ne

  
Value is not equal to `n`  
<Section>
```typescript
import { ne } from "drizzle-orm";

db.select().from(table).where(ne(table.column, 5));
```

```sql
SELECT * FROM table WHERE table.column <> 5
```
</Section>

<Section>
```typescript
import { ne } from "drizzle-orm";

db.select().from(table).where(ne(table.column1, table.column2));
```

```sql
SELECT * FROM table WHERE table.column1 <> table.column2
```
</Section>

## ---

### gt
 
  
Value is greater than `n`
<Section>
```typescript
import { gt } from "drizzle-orm";

db.select().from(table).where(gt(table.column, 5));
```

```sql
SELECT * FROM table WHERE table.column > 5
```
</Section>

<Section>
```typescript
import { gt } from "drizzle-orm";

db.select().from(table).where(gt(table.column1, table.column2));
```

```sql
SELECT * FROM table WHERE table.column1 > table.column2
```
</Section>

### gte

  
Value is greater than or equal to `n`
<Section>
```typescript
import { gte } from "drizzle-orm";

db.select().from(table).where(gte(table.column, 5));
```

```sql
SELECT * FROM table WHERE table.column >= 5
```
</Section>

<Section>
```typescript
import { gte } from "drizzle-orm";

db.select().from(table).where(gte(table.column1, table.column2));
```

```sql
SELECT * FROM table WHERE table.column1 >= table.column2
```
</Section>

### lt

  
Value is less than `n`
<Section>
```typescript
import { lt } from "drizzle-orm";

db.select().from(table).where(lt(table.column, 5));
```

```sql
SELECT * FROM table WHERE table.column < 5
```
</Section>

<Section>
```typescript
import { lt } from "drizzle-orm";

db.select().from(table).where(lt(table.column1, table.column2));
```

```sql
SELECT * FROM table WHERE table.column1 < table.column2
```
</Section>

### lte

  
Value is less than or equal to `n`.

<Section>
```typescript
import { lte } from "drizzle-orm";

db.select().from(table).where(lte(table.column, 5));
```

```sql
SELECT * FROM table WHERE table.column <= 5
```
</Section>

<Section>
```typescript
import { lte } from "drizzle-orm";

db.select().from(table).where(lte(table.column1, table.column2));
```

```sql
SELECT * FROM table WHERE table.column1 <= table.column2
```
</Section>

## ---

### exists

  
Value exists
<Section>
```typescript
import { exists } from "drizzle-orm";

const query = db.select().from(table2)
db.select().from(table).where(exists(query));
```

```sql
SELECT * FROM table WHERE EXISTS (SELECT * from table2)
```
</Section>

### notExists

<Section>
```typescript
import { notExists } from "drizzle-orm";

const query = db.select().from(table2)
db.select().from(table).where(notExists(query));
```

```sql
SELECT * FROM table WHERE NOT EXISTS (SELECT * from table2)
```
</Section>

### isNull

  
Value is `null`
<Section>
```typescript
import { isNull } from "drizzle-orm";

db.select().from(table).where(isNull(table.column));
```

```sql
SELECT * FROM table WHERE table.column IS NULL
```
</Section>

### isNotNull

  
Value is not `null`
<Section>
```typescript
import { isNotNull } from "drizzle-orm";

db.select().from(table).where(isNotNull(table.column));
```

```sql
SELECT * FROM table WHERE table.column IS NOT NULL
```
</Section>

## ---

### inArray

  
Value is in array of values
<Section>
```typescript
import { inArray } from "drizzle-orm";

db.select().from(table).where(inArray(table.column, [1, 2, 3, 4]));
```

```sql
SELECT * FROM table WHERE table.column in (1, 2, 3, 4)
```
</Section>

<Section>
```typescript
import { inArray } from "drizzle-orm";

const query = db.select({ data: table2.column }).from(table2);
db.select().from(table).where(inArray(table.column, query));
```

```sql
SELECT * FROM table WHERE table.column IN (SELECT table2.column FROM table2)
```
</Section>

### notInArray

  
Value is not in array of values
<Section>
```typescript
import { notInArray } from "drizzle-orm";

db.select().from(table).where(notInArray(table.column, [1, 2, 3, 4]));
```

```sql
SELECT * FROM table WHERE table.column NOT in (1, 2, 3, 4)
```
</Section>

<Section>
```typescript
import { notInArray } from "drizzle-orm";

const query = db.select({ data: table2.column }).from(table2);
db.select().from(table).where(notInArray(table.column, query));
```

```sql
SELECT * FROM table WHERE table.column NOT IN (SELECT table2.column FROM table2)
```
</Section>

## ---

### between

  
Value is between two values
<Section>
```typescript
import { between } from "drizzle-orm";

db.select().from(table).where(between(table.column, 2, 7));
```

```sql
SELECT * FROM table WHERE table.column BETWEEN 2 AND 7
```
</Section>

### notBetween

  
Value is not between two value
<Section>
```typescript
import { notBetween } from "drizzle-orm";

db.select().from(table).where(notBetween(table.column, 2, 7));
```

```sql
SELECT * FROM table WHERE table.column NOT BETWEEN 2 AND 7
```
</Section>

## ---

### like

  
Value is like other value, case sensitive
<Section>
```typescript
import { like } from "drizzle-orm";

db.select().from(table).where(like(table.column, "%llo wor%"));
```

```sql
SELECT * FROM table  WHERE table.column LIKE '%llo wor%'
```
</Section>

### notIlike

  
Value is not like some other value, case insensitive
<Section>
```typescript
import { notIlike } from "drizzle-orm";

db.select().from(table).where(notIlike(table.column, "%llo wor%"));
```

```sql
SELECT * FROM table WHERE table.column NOT ILIKE '%llo wor%'
```
</Section>

## ---

### not

  
All conditions must return `false`.

<Section>
```typescript
import { eq, not } from "drizzle-orm";

db.select().from(table).where(not(eq(table.column, 5)));
```

```sql
SELECT * FROM table WHERE NOT (table.column = 5)
```
</Section>

### and

  
All conditions must return `true`.

<Section>
```typescript
import { gt, lt, and } from "drizzle-orm";

db.select().from(table).where(and(gt(table.column, 5), lt(table.column, 7)));
```

```sql
SELECT * FROM table WHERE (table.column > 5 AND table.column < 7)
```
</Section>

### or

  
One or more conditions must return `true`.

<Section>
```typescript
import { gt, lt, or } from "drizzle-orm";

db.select().from(table).where(or(gt(table.column, 5), lt(table.column, 7)));
```

```sql
SELECT * FROM table WHERE (table.column > 5 OR table.column < 7)
```
</Section>

## ---


Source: https://orm.drizzle.team/docs/singlestore/perf-queries

# Query performance
When it comes to **Drizzle** — we're a thin TypeScript layer on top of SQL with 
almost 0 overhead and to make it actual 0, you can utilise our prepared statements API.
  
**When you run a query on the database, there are several things that happen:**
- all the configurations of the query builder got concatenated to the SQL string
- that string and params are sent to the database driver
- driver compiles SQL query to the binary SQL executable format and sends it to the database

With prepared statements you do SQL concatenation once on the Drizzle ORM side and then database 
driver is able to reuse precompiled binary SQL instead of parsing query all the time. 
It has extreme performance benefits on large SQL queries.  

Different database drivers support prepared statements in different ways and sometimes 
Drizzle ORM you can go [**faster than better-sqlite3 driver.**](https://twitter.com/_alexblokh/status/1593593415907909634)

## Prepared statement

```typescript copy {3}
    const db = drizzle(...);

    const prepared = db.select().from(customers).prepare();
    
    const res1 = await prepared.execute();
    const res2 = await prepared.execute();
    const res3 = await prepared.execute();
    ```

## Placeholder
Whenever you need to embed a dynamic runtime value - you can use the `sql.placeholder(...)` api

```ts copy {6,9-10,15,18}
    import { sql } from "drizzle-orm";

    const p1 = db
      .select()
      .from(customers)
      .where(eq(customers.id, sql.placeholder('id')))
      .prepare()

    await p1.execute({ id: 10 }) // SELECT * FROM customers WHERE id = 10
    await p1.execute({ id: 12 }) // SELECT * FROM customers WHERE id = 12

    const p2 = db
      .select()
      .from(customers)
      .where(sql`lower(${customers.name}) like ${sql.placeholder('name')}`)
      .prepare();

    await p2.execute({ name: '%an%' }) // SELECT * FROM customers WHERE lower(name) like '%an%'
    ```


Source: https://orm.drizzle.team/docs/singlestore/query-utils

import $count from '@mdx/$count.mdx';

# Drizzle query utils

### $count
<$count/>

Source: https://orm.drizzle.team/docs/singlestore/read-replicas

# Read Replicas

When your project involves a set of read replica instances, and you require a convenient method for managing 
SELECT queries from read replicas, as well as performing create, delete, and update operations on the primary 
instance, you can leverage the `withReplicas()` function within Drizzle

```ts copy
import { drizzle } from "drizzle-orm/singlestore";
import mysql from "mysql2/promise";
import { boolean, int, singlestoreTable, text, withReplicas } from 'drizzle-orm/singlestore-core';

const usersTable = singlestoreTable('users', {
	id: int('id').primaryKey().autoincrement(),
	name: text('name').notNull(),
	verified: boolean('verified').notNull().default(false),
});

const primaryClient = await mysql.createConnection({
  host: "host",
  user: "user",
  database: "primary_db",
})
const primaryDb = drizzle({ client: primaryClient });

const read1Client = await mysql.createConnection({
  host: "host",
  user: "user",
  database: "read_1",
})
const read1 = drizzle({ client: read1Client });

const read2Client = await mysql.createConnection({
  host: "host",
  user: "user",
  database: "read_2",
})
const read2 = drizzle({ client: read2Client });

const db = withReplicas(primaryDb, [read1, read2]);
```

You can now use the `db` instance the same way you did before. Drizzle will 
handle the choice between read replica and the primary instance automatically

```ts
// Read from either the read1 connection or the read2 connection
await db.select().from(usersTable)

// Use the primary database for the delete operation
await db.delete(usersTable).where(eq(usersTable.id, 1))
```

You can use the `$primary` key to force using primary instances even for read operations

```ts
// read from primary
await db.$primary.select().from(usersTable);
```

With Drizzle, you can also specify custom logic for choosing read replicas. 
You can make a weighted decision or any other custom selection method for random read replica choice. 
Here is an 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 selected.

Keep in mind that you can implement any type of random selection method 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]!
});

await db.select().from(usersTable)
```


Source: https://orm.drizzle.team/docs/singlestore/relations-v1-v2

import Callout from '@mdx/Callout.astro';
import Prerequisites from "@mdx/Prerequisites.astro";
import Section from '@mdx/Section.astro';
import Npx from "@mdx/Npx.astro";
import Npm from "@mdx/Npm.astro";
import CodeTabs from '@mdx/CodeTabs.astro';
import CodeTab from '@mdx/CodeTab.astro';

# Migrating to Relational Queries version 2

<Npm>
 drizzle-orm@rc
 drizzle-kit@rc -D
</Npm>

<br/>

<Prerequisites>
- **Relations Fundamentals** - [read here](/docs/relations-schema-declaration)
- **drizzle-kit pull** - [read here](/docs/drizzle-kit-pull)
</Prerequisites>

<Callout>
Below is the table of contents. Click an item to jump to that section:

- [What is working differently from v1](#what-is-working-differently-from-v1)  
- [New features in v2](#what-is-new)  
- [How to migrate relations definition from v1 to v2](#how-to-migrate-relations-schema-definition-from-v1-to-v2)  
- [How to migrate queries from v1 to v2](#how-to-migrate-queries-from-v1-to-v2)  
- [Internal changes(imports, internal types, etc.)](#internal-changes)
</Callout>

### API changes
#### What is working differently from v1

{/* ##### Drizzle Relations schema definition */}

One of the biggest updates were in **Relations Schema definition**

The first difference is that you no longer need to specify `relations` for each table separately in different objects and
then pass them all to `drizzle()` along with your schema. In Relational Queries v2, you now have one dedicated place to
specify all the relations for all the tables you need.

The `r` parameter in the callback provides comprehensive autocomplete
functionality - including all tables from your schema and functions such as `one`, `many`, and `through` - essentially
offering everything you need to specify your relations.

```ts
// relations.ts
import * as schema from "./schema"
import { defineRelations } from "drizzle-orm"

export const relations = defineRelations(schema, (r) => ({
    ...
}));
```
```ts
// index.ts
import { relations } from "./relations"
import { drizzle } from "drizzle-orm/..."

const db = drizzle(process.env.DATABASE_URL, { relations })
```

##### What is different?

<Callout collapsed="Schema Definition">
```ts copy
import * as p from 'drizzle-orm/pg-core';

export const users = p.pgTable('users', {
	id: p.integer().primaryKey(),
	name: p.text(),
	invitedBy: p.integer('invited_by'),
});

export const posts = p.pgTable('posts', {
	id: p.integer().primaryKey(),
	content: p.text(),
	authorId: p.integer('author_id'),
});
```
</Callout>

**One place for all your relations**

<Callout title="❌ v1">
```ts
import { relations } from "drizzle-orm/_relations";
import { users, posts } from './schema';

export const usersRelation = relations(users, ({ one, many }) => ({
  invitee: one(users, {
    fields: [users.invitedBy],
    references: [users.id],
  }),
  posts: many(posts),
}));

export const postsRelation = relations(posts, ({ one, many }) => ({
  author: one(users, {
    fields: [posts.authorId],
    references: [users.id],
  }),
}));
```
</Callout>

<Callout title='✅ v2'>
```ts
import { defineRelations } from "drizzle-orm";
import * as schema from "./schema";

export const relations = defineRelations(schema, (r) => ({
  users: {
    invitee: r.one.users({
      from: r.users.invitedBy,
      to: r.users.id,
    }),
    posts: r.many.posts(),
  },
  posts: {
    author: r.one.users({
      from: r.posts.authorId,
      to: r.users.id,
    }),
  },
}));
```
</Callout>

You can still separate it into different `parts`, and you can make the parts any size you want

```ts
import { defineRelations, defineRelationsPart } from 'drizzle-orm';
import * as schema from "./schema";

export const relations = defineRelations(schema, (r) => ({
  users: {
    invitee: r.one.users({
      from: r.users.invitedBy,
      to: r.users.id,
    }),
    posts: r.many.posts(),
  }
}));

export const part = defineRelationsPart(schema, (r) => ({
  posts: {
    author: r.one.users({
      from: r.posts.authorId,
      to: r.users.id,
    }),
  }
}));
```

and then you can provide it to the db instance

```ts
const db = drizzle(process.env.DB_URL, { relations: { ...relations, ...part } })
```

**Define `many` without `one`**

In v1, if you wanted only the `many` side of a relationship, you had to specify the `one` side on the other end, 
which made for a poor developer experience.

In v2, you can simply use the `many` side without any additional steps

<Callout title="❌ v1">
```ts
import { relations } from "drizzle-orm/_relations";
import { users, posts } from './schema';

export const usersRelation = relations(users, ({ one, many }) => ({
  posts: many(posts),
}));

export const postsRelation = relations(posts, ({ one, many }) => ({
  author: one(users, {
    fields: [posts.authorId],
    references: [users.id],
  }),
}));
```
</Callout>

<Callout title='✅ v2'>
```ts
import { defineRelations } from "drizzle-orm";
import * as schema from "./schema";

export const relations = defineRelations(schema, (r) => ({
  users: {
    posts: r.many.posts({
      from: r.users.id,
      to: r.posts.authorId,
    }),
  },
}));
```
</Callout>

**New `optional` option**

`optional: false` at the type level makes the `author` key in the `posts` object required. 
This should be used when you are certain that this specific entity will always exist.

<Callout title="❌ v1">
Was not supported in v1
</Callout>

<Callout title='✅ v2'>
```ts {9}
import { defineRelations } from "drizzle-orm";
import * as schema from "./schema";

export const relations = defineRelations(schema, (r) => ({
  posts: {
    author: r.one.users({
      from: r.posts.authorId,
      to: r.users.id,
      optional: false,
    }),
  },
}));
```
</Callout>

**No modes in `drizzle()`**

We found a way to use the same strategy for all MySQL dialects, so there's no need to specify them

<Callout title="❌ v1">
```ts
import * as schema from './schema'

const db = drizzle(process.env.DATABASE_URL, { mode: "planetscale", schema });
// or
const db = drizzle(process.env.DATABASE_URL, { mode: "default", schema });
```
</Callout>

<Callout title='✅ v2'>
```ts
import { relations } from './relations'

const db = drizzle(process.env.DATABASE_URL, { relations });
```
</Callout>

**`from` and `to` upgrades**

We've renamed `fields` to `from` and `references` to `to`, and we made both accept either a single value or an array

<Callout title="❌ v1">
```ts
...
author: one(users, {
  fields: [posts.authorId],
  references: [users.id],
}),
...
```
</Callout>

<Callout title='✅ v2'>
```ts
... 
author: r.one.users({
  from: r.posts.authorId,
  to: r.users.id,
}),
...
```
```ts
... 
author: r.one.users({
  from: [r.posts.authorId],
  to: [r.users.id],
}),
...
```
</Callout>

**`relationName` -> `alias`**

<Callout title="❌ v1">
```ts {8}
import { relations } from "drizzle-orm/_relations";
import { users, posts } from './schema';

export const postsRelation = relations(posts, ({ one }) => ({
  author: one(users, {
    fields: [posts.authorId],
    references: [users.id],
	  relationName: "author_post",
  }),
}));
```
</Callout>

<Callout title='✅ v2'>
```ts {9}
import { defineRelations } from "drizzle-orm";
import * as schema from "./schema";

export const relations = defineRelations(schema, (r) => ({
  posts: {
    author: r.one.users({
      from: r.posts.authorId,
      to: r.users.id,
      alias: "author_post",
    }),
  },
}));
```
</Callout>

**`custom types` new function**

There is a new [codec](/docs/codecs) function was added to custom types, so you can control how data is mapped

You can find out more [here](/docs/custom-types#ts-doc-for-type-definitions)

<Callout title='✅ v2'>
```ts
const customBytes = customType<{
  data: Buffer;
  driverData: Buffer;
  jsonData: string;
}>({
  dataType: () => "bytea",
  codec: "bytea",
});
```

</Callout>

##### What is new?

**`through` for many-to-many relations**

Previously, you would need to query through a junction table and then map it out for every response

You don't need to do it now!

<Callout collapsed='Schema'>
```ts
import * as p from "drizzle-orm/pg-core";

export const users = p.pgTable("users", {
  id: p.integer().primaryKey(),
  name: p.text(),
  verified: p.boolean().notNull(),
});

export const groups = p.pgTable("groups", {
  id: p.integer().primaryKey(),
  name: p.text(),
});

export const usersToGroups = p.pgTable(
  "users_to_groups",
  {
    userId: p
      .integer("user_id")
      .notNull()
      .references(() => users.id),
    groupId: p
      .integer("group_id")
      .notNull()
      .references(() => groups.id),
  },
  (t) => [p.primaryKey({ columns: [t.userId, t.groupId] })]
);
```
</Callout>

<Callout title="❌ v1">
```ts
export const usersRelations = relations(users, ({ many }) => ({
  usersToGroups: many(usersToGroups),
}));

export const groupsRelations = relations(groups, ({ many }) => ({
  usersToGroups: many(usersToGroups),
}));

export const usersToGroupsRelations = relations(usersToGroups, ({ one }) => ({
  group: one(groups, {
    fields: [usersToGroups.groupId],
    references: [groups.id],
  }),
  user: one(users, {
    fields: [usersToGroups.userId],
    references: [users.id],
  }),
}));
```
```ts
// Query example
const response = await db.query.users.findMany({
  with: {
    usersToGroups: {
      columns: {},
      with: {
        group: true,
      },
    },
  },
});
```
</Callout>

<Callout title='✅ v2'>
```ts
import * as schema from './schema';
import { defineRelations } from 'drizzle-orm';

export const relations = defineRelations(schema, (r) => ({
  users: {
    groups: r.many.groups({
      from: r.users.id.through(r.usersToGroups.userId),
      to: r.groups.id.through(r.usersToGroups.groupId),
    }),
  },
  groups: {
    participants: r.many.users(),
  },
}));
```
```ts
// Query example
const response = await db.query.users.findMany({
  with: {
    groups: true,
  },
});
```
</Callout>

**Predefined filters**

<Callout title="❌ v1">
Was not supported in v1
</Callout>

<Callout title='✅ v2'>
```ts {10-12}
import * as schema from './schema';
import { defineRelations } from 'drizzle-orm';

export const relations = defineRelations(schema,
  (r) => ({
    groups: {
      verifiedUsers: r.many.users({
        from: r.groups.id.through(r.usersToGroups.groupId),
        to: r.users.id.through(r.usersToGroups.userId),
        where: {
          verified: true,
        },
      }),
    },
  })
);
```
```ts {4}
// Query example: get groups with all verified users
const response = await db.query.groups.findMany({
  with: {
    verifiedUsers: true,
  },
});
```
</Callout>

##### `where` is now object

<Callout title="❌ v1">
```ts
const response = db._query.users.findMany({
  where: (users, { eq }) => eq(users.id, 1),
});
```
</Callout>

<Callout title="✅ v2">
```ts
const response = db.query.users.findMany({
  where: {
    id: 1,
  },
});
```

For a complete API Reference please check our [Select Filters docs](/docs/rqb#select-filters)
</Callout>

<Callout collapsed='Complex filter example using RAW'>
```ts
// schema.ts
import { integer, jsonb, pgTable, text, timestamp } from "drizzle-orm/pg-core";

export const users = pgTable("users", {
  id: integer().primaryKey(),
  name: text(),
  email: text().notNull(),
  age: integer(),
  createdAt: timestamp("created_at").defaultNow(),
  lastLogin: timestamp("last_login"),
  subscriptionEnd: timestamp("subscription_end"),
  lastActivity: timestamp("last_activity"),
  preferences: jsonb(),      // JSON column for user settings/preferences
  interests: text().array(),     // Array column for user interests
});
```
```ts
const response = await db.query.users.findMany({
  where: {
    AND: [
      {
        OR: [
          { RAW: (table) => sql`LOWER(${table.name}) LIKE 'john%'` },
          { name: { ilike: "jane%" } },
        ],
      },
      {
        OR: [
          { RAW: (table) => sql`${table.preferences}->>'theme' = 'dark'` },
          { RAW: (table) => sql`${table.preferences}->>'theme' IS NULL` },
        ],
      },
      { RAW: (table) => sql`${table.age} BETWEEN 25 AND 35` },
    ],
  },
});
```
</Callout>

##### `orderBy` is now object

<Callout title="❌ v1">
```ts
const response = db._query.users.findMany({
  orderBy: (users, { asc }) => [asc(users.id)],
});
```
</Callout>

<Callout title="✅ v2">
```ts
const response = db.query.users.findMany({
  orderBy: { id: "asc" },
});
```
</Callout>

##### Filtering by relations

<Callout title="❌ v1">
Was not supported in v1
</Callout>

<Callout title='✅ v2'>
Example: Get all users whose ID>10 and who have at least one post with content starting with “M”

```ts
const usersWithPosts = await db.query.usersTable.findMany({
  where: {
    id: {
      gt: 10
    },
    posts: {
      content: {
        like: 'M%'
      }
    }
  },
});
```
</Callout>

##### Using offset on related objects

<Callout title="❌ v1">
Was not supported in v1
</Callout>

<Callout title='✅ v2'>
```ts
await db.query.posts.findMany({
	limit: 5,
	offset: 2, // correct ✅
	with: {
		comments: {
			offset: 3, // correct ✅
			limit: 3,
		},
	},
});
```
</Callout>

#### How to migrate relations schema definition from v1 to v2

##### **Option 1**: Using `drizzle-kit pull`

In new version `drizzle-kit pull` supports pulling `relations.ts` file in a new syntax:

##### Step 1

<Npx>
drizzle-kit pull
</Npx>

#### Step 2 

Transfer generated relations code from `drizzle/relations.ts` to the file you are using to specify your relations 
```plaintext {4-5}
 ├ 📂 drizzle
 │ ├ 📂 meta
 │ ├ 📜 migration.sql
 │ ├ 📜 relations.ts ────────┐
 │ └ 📜 schema.ts            |
 ├ 📂 src                    │ 
 │ ├ 📂 db                   │
 │ │ ├ 📜 relations.ts <─────┘
 │ │ └ 📜 schema.ts 
 │ └ 📜 index.ts         
 └ …
```

<Callout>
`drizzle/relations.ts` includes an import of all tables from `drizzle/schema.ts`, which looks like this:
```ts
import * as schema from './schema'
```

You may need to change this import to a file where ALL your schema tables are located. 

If there are multiple schema files, you can do the following:
```ts
import * as schema1 from './schema1'
import * as schema2 from './schema2'
...
```
</Callout>

#### Step 3

Change drizzle database instance creation and provide `relations` object instead of `schema`

<Callout title='Before'>
```ts
import * as schema from './schema'
import { drizzle } from 'drizzle-orm/...'

const db = drizzle('<url>', { schema })
```
</Callout>

<Callout title='After'>
```ts
// should be imported from a file in Step 2
import { relations } from './relations'
import { drizzle } from 'drizzle-orm/...'

const db = drizzle('<url>', { relations })
```
</Callout>

<Callout>
If you had MySQL dialect, you can remove `mode` from `drizzle()` as long as it's not needed in version 2
</Callout>

##### **Option 2**: Manual migration

If you want to migrate manually, you can check our [Drizzle Relations section](/docs/relations) for the complete API reference and examples of one-to-one, one-to-many, and many-to-many relations.

#### How to migrate queries from v1 to v2

##### Migrate `where` statements

You can check our [Select Filters docs](/docs/rqb#select-filters) to see examples and a complete API reference.

With the new syntax, you can use `AND`, `OR`, `NOT`, and `RAW`, plus all the filtering operators that 
were previously available in Relations v1.

**Examples**
<CodeTabs items={["simple eq", "using AND", "using OR", "using NOT", "complex example using RAW"]}>
<CodeTab>
```ts
const response = await db.query.users.findMany({
  where: {
    age: 15,
  },
});
```
```sql {8}
select
  "d0"."id" as "id",
  "d0"."name" as "name",
  "d0"."age" as "age"
from
  "users" as "d0"
where
  "d0"."age" = 15
```
</CodeTab>
<CodeTab>
```ts
const response = await db.query.users.findMany({
  where: {
    age: 15,
    name: 'John'
  },
});
```
```sql {9-10}
select
  "d0"."id" as "id",
  "d0"."name" as "name",
  "d0"."age" as "age"
from
  "users" as "d0"
where
  (
    ("d0"."age" = 15)
    and ("d0"."name" = 'John')
  )
```
</CodeTab>
<CodeTab>
```ts
const response = await db.query.users.findMany({
  where: {
    OR: [
      {
        id: {
          gt: 10,
        },
      },
      {
        name: {
          like: "John%",
        },
      },
    ],
  },
});
```
```sql {9-10}
select
  "d0"."id" as "id",
  "d0"."name" as "name",
  "d0"."age" as "age"
from
  "users" as "d0"
where
  (
    ("d0"."id" > 10)
    or ("d0"."name" like 'John%')
  )
```
</CodeTab>
<CodeTab>
```ts
const response = await db.query.users.findMany({
  where: {
    NOT: {
      id: {
        gt: 10,
      },
    },
    name: {
      like: "John%",
    },
  },
});
```
```sql {9-10}
select
  "d0"."id" as "id",
  "d0"."name" as "name",
  "d0"."age" as "age"
from
  "users" as "d0"
where
  (
    (not ("d0"."id" > 10))
    and ("d0"."name" like 'John%')
  )
```
</CodeTab>
<CodeTab>
```ts
// schema.ts
import { integer, jsonb, pgTable, text, timestamp } from "drizzle-orm/pg-core";

export const users = pgTable("users", {
  id: integer().primaryKey(),
  name: text(),
  email: text().notNull(),
  age: integer(),
  createdAt: timestamp("created_at").defaultNow(),
  lastLogin: timestamp("last_login"),
  subscriptionEnd: timestamp("subscription_end"),
  lastActivity: timestamp("last_activity"),
  preferences: jsonb(),      // JSON column for user settings/preferences
  interests: text().array(),     // Array column for user interests
});
```
```ts
const response = await db.query.users.findMany({
  where: {
    AND: [
      {
        OR: [
          { RAW: (table) => sql`LOWER(${table.name}) LIKE 'john%'` },
          { name: { ilike: "jane%" } },
        ],
      },
      {
        OR: [
          { RAW: (table) => sql`${table.preferences}->>'theme' = 'dark'` },
          { RAW: (table) => sql`${table.preferences}->>'theme' IS NULL` },
        ],
      },
      { RAW: (table) => sql`${table.age} BETWEEN 25 AND 35` },
    ],
  },
});
```
```sql
SELECT
  "d0"."id" AS "id",
  "d0"."name" AS "name",
  "d0"."email" AS "email",
  "d0"."age" AS "age",
  "d0"."created_at" AS "createdAt",
  "d0"."last_login" AS "lastLogin",
  "d0"."subscription_end" AS "subscriptionEnd",
  "d0"."last_activity" AS "lastActivity",
  "d0"."preferences" AS "preferences",
  "d0"."interests" AS "interests"
FROM
  "users" AS "d0"
WHERE
  (
    (
      (
        (LOWER("d0"."name") LIKE 'john%')
        OR ("d0"."name" ILIKE 'jane%')
      )
    )
    AND (
      (
        ("d0"."preferences" ->> 'theme' = 'dark')
        OR ("d0"."preferences" ->> 'theme' IS NULL)
      )
    )
    AND ("d0"."age" BETWEEN 25 AND 35)
  )
```
</CodeTab>
</CodeTabs>

##### Migrate `orderBy` statements

Order by was simplified to a single object, where you specify the column and the sort direction (`asc` or `desc`)

<Callout title="❌ v1">
```ts
const response = db._query.users.findMany({
  orderBy: (users, { asc }) => [asc(users.id)],
});
```
</Callout>

<Callout title="✅ v2">
```ts
const response = db.query.users.findMany({
  orderBy: { id: "asc" },
});
```
</Callout>

##### Migrate `many-to-many` queries

Relational Queries v1 had a very complex way of managing many-to-many queries.
You had to use junction tables to query through them explicitly, and then map those tables out, like this:

```ts
const response = await db.query.users.findMany({
  with: {
    usersToGroups: {
      columns: {},
      with: {
        group: true,
      },
    },
  },
});
```

After upgrading to Relational Queries v2, your many-to-many relation will look like this:

```ts
import * as schema from './schema';
import { defineRelations } from 'drizzle-orm';

export const relations = defineRelations(schema, (r) => ({
  users: {
    groups: r.many.groups({
      from: r.users.id.through(r.usersToGroups.userId),
      to: r.groups.id.through(r.usersToGroups.groupId),
    }),
  },
  groups: {
    participants: r.many.users(),
  },
}));
```

And when you migrate your query, it will become this:

```ts
// Query example
const response = await db.query.users.findMany({
  with: {
    groups: true,
  },
});
```

### Internal changes

1. Every `drizzle` database, `session`, `migrator` and `transaction` instance updated with new generic arguments for RQB v2 queries

<Callout collapsed='Examples'>
**migrator**
<Callout type='error' title='before'>
```ts
export async function migrate<
  TSchema extends Record<string, unknown>
>(
  db: NodePgDatabase<TSchema>,
  config: MigrationConfig,
) {
  ...
}
```
</Callout>
<Callout title='now'>
```ts {1,2}
export async function migrate<TRelations extends AnyRelations>(
	db: NodePgDatabase<TRelations>,
	config: MigrationConfig,
) {
  ...
}
```
</Callout>
**session**
<Callout type='error' title='before'>
```ts
export class NodePgSession<
	TFullSchema extends Record<string, unknown>,
	TSchema extends V1.TablesRelationalConfig,
> extends PgSession<NodePgQueryResultHKT, TFullSchema, TSchema>
```
</Callout>
<Callout title='now'>
```ts {2,3}
export class NodePgSession<
	TRelations extends AnyRelations,
> extends PgAsyncSession<NodePgQueryResultHKT, TRelations>
```
</Callout>
**transaction**
<Callout type='error' title='before'>
```ts
export class NodePgTransaction<
	TFullSchema extends Record<string, unknown>,
	TSchema extends V1.TablesRelationalConfig,
> extends PgTransaction<NodePgQueryResultHKT, TFullSchema, TSchema>
```
</Callout>
<Callout title='now'>
```ts {2,3}
export class NodePgTransaction<
	TRelations extends AnyRelations,
> extends PgAsyncTransaction<NodePgQueryResultHKT, TRelations>
```
</Callout>
**driver**
<Callout type='error' title='before'>
```ts
export class NodePgDatabase<
	TSchema extends Record<string, unknown> = Record<string, never>,
> extends PgDatabase<NodePgQueryResultHKT, TSchema>
```
</Callout>
<Callout title='now'>
```ts {2,3}
export class NodePgDatabase<
	TRelations extends AnyRelations = EmptyRelations,
> extends PgAsyncDatabase<NodePgQueryResultHKT, TRelations> 
```
</Callout>
</Callout>

2. Updated `DrizzleConfig` generic with `TRelations` argument and `relations: TRelations` field

<Callout collapsed='Examples'>
<Callout type='error' title='before'>
```ts
export interface DrizzleConfig<
  TSchema extends Record<string, unknown> = Record<string, never>
> {
  logger?: boolean | Logger;
  schema?: TSchema;
  casing?: Casing;
}
```
</Callout>

<Callout title='now'>
```ts {2,5}
export interface DrizzleConfig<
	TRelationConfigs extends AnyRelations = EmptyRelations,
> {
	logger?: boolean | Logger | undefined;
	relations?: TRelationConfigs | undefined;
	cache?: Cache | undefined;
	jit?: boolean | undefined;
}
```
</Callout>
</Callout>

3. The following entities have been removed from `drizzle-orm` and `drizzle-orm/relations`. The original imports now 
include new types used by Relational Queries v2, so make sure to update your imports if you intend to use the older types:

<Callout collapsed='A list of all removed entities'>
- `Relations`
- `TableRelationsKeysOnly`
- `ExtractTableRelationsFromSchema`
- `ExtractRelationsFromTableExtraConfigSchema`
- `getOperators`
- `FindTableByDBName`
- `RelationalSchemaConfig`
- `RelationConfig`
- `extractTablesRelationalConfig`
- `relations`
- `createOne`
- `createMany`
- `NormalizedRelation`
- `normalizeRelation`
- `createTableRelationsHelpers`
- `TableRelationsHelpers`
</Callout>

4. In the same manner, `${dialect}-core/query-builders/query` files were updated with RQB v2's alternatives

<Callout collapsed='Examples'>
```ts
import { RelationalQueryBuilder, PgRelationalQuery } from 'drizzle-orm/pg-core/query-builders/query';
```
</Callout>


Source: https://orm.drizzle.team/docs/singlestore/relations-v2

import Tab from '@mdx/Tab.astro';
import Tabs from '@mdx/Tabs.astro';
import IsSupportedChipGroup from '@mdx/IsSupportedChipGroup.astro';
import Callout from '@mdx/Callout.astro';
import Section from '@mdx/Section.astro';
import Prerequisites from "@mdx/Prerequisites.astro";
import CodeTab from '@mdx/CodeTab.astro';
import CodeTabs from '@mdx/CodeTabs.astro';
import Npm from '@mdx/Npm.astro';

# Drizzle relations

<Npm>
 drizzle-orm@rc
 drizzle-kit@rc -D
</Npm>

<br/>

<Prerequisites>  
  - **Relations Fundamentals** - get familiar with the concepts of foreign key constraints, soft relations, database normalization, etc - [read here](/docs/relations-schema-declaration)
  - **Declare schema** - get familiar with how to define drizzle schemas - [read here](/docs/sql-schema-declaration)
  - **Database connection** - get familiar with how to connect to database using drizzle - [read here](/docs/get-started-postgresql)
</Prerequisites>

The sole purpose of Drizzle relations is to let you query your relational data in the most simple and concise way:

<CodeTabs items={["Relational queries", "Select with joins"]}>
<Section>
```ts
import { drizzle } from 'drizzle-orm/…';
import { defineRelations } from 'drizzle-orm';
import * as p from 'drizzle-orm/pg-core';

export const users = p.pgTable('users', {
	id: p.integer().primaryKey(),
	name: p.text().notNull()
});

export const posts = p.pgTable('posts', {
	id: p.integer().primaryKey(),
	content: p.text().notNull(),
	ownerId: p.integer('owner_id'),
});

const relations = defineRelations({ users, posts }, (r) => ({
	posts: {
		author: r.one.users({
			from: r.posts.ownerId,
			to: r.users.id,
		}),
	}
}))

const db = drizzle(client, { relations });

const result = db.query.posts.findMany({
  with: {
    author: true,
  },
});
```
```ts
[{
  id: 10,
  content: "My first post!",
  author: {
    id: 1,
    name: "Alex"
  }
}]
```
</Section>
<Section>
```ts
import { drizzle } from 'drizzle-orm/…';
import { eq } from 'drizzle-orm';
import { posts, users } from './schema';

const db = drizzle(client);

const res = await db.select()
                    .from(posts)
                    .leftJoin(users, eq(posts.ownerId, users.id))
                    .orderBy(posts.id)

const mappedResult = ...
```
</Section>
</CodeTabs>

### `one()`
Here is a list of all fields available for `.one()` in drizzle relations

```ts {3-11}
const relations = defineRelations({ users, posts }, (r) => ({
	posts: {
		author: r.one.users({
			from: r.posts.ownerId,
			to: r.users.id,
			optional: false,
      alias: 'custom_name',
			where: {
				verified: true,
			}
		}),
	}
}))
```

- `author` key is a custom key that appears in the `posts` object when using Drizzle relational queries.
- `r.one.users` defines that `author` will be a single object from the `users` table rather than an array of objects.
- `from: r.posts.ownerId` specifies the table from which we are establishing a soft relation. 
In this case, the relation starts from the `ownerId` column in the `posts` table.
- `to: r.users.id` specifies the table to which we are establishing a soft relation. 
In this case, the relation points to the `id` column in the `users` table.
- `optional: false` at the type level makes the `author` key in the posts object `required`. 
This should be used when you are certain that this specific entity will always exist.
- `alias` is used to add a specific alias to relationships between tables. If you have multiple identical relationships between two tables, you should 
differentiate them using `alias`
- `where` condition can be used for polymorphic relations. It fetches relations based on a `where` statement.
For example, in the case above, only `verified authors` will be retrieved. Learn more about polymorphic relations [here](/docs/relations-schema-declaration#polymorphic-relations).

### `many()`

Here is a list of all fields available for `.many()` in drizzle relations

```ts {3-10}
const relations = defineRelations({ users, posts }, (r) => ({
	users: {
		feed: r.many.posts({
			from: r.users.id,
			to: r.posts.ownerId,
			alias: 'custom_name',
			where: {
				approved: true,
			}
		}),
	}
}))
```

- `feed` key is a custom key that appears in the `users` object when using Drizzle relational queries.
- `r.many.posts` defines that `feed` will be an array of objects from the `posts` table rather than just an object
- `from: r.users.id` specifies the table from which we are establishing a soft relation. 
In this case, the relation starts from the `id` column in the `users` table.
- `to: r.posts.ownerId` specifies the table to which we are establishing a soft relation. 
In this case, the relation points to the `ownerId` column in the `posts` table.
- `alias` is used to add a specific alias to relationships between tables. If you have multiple identical relationships between two tables, you should 
differentiate them using `alias`
- `where` condition can be used for polymorphic relations. It fetches relations based on a `where` statement.
For example, in the case above, only `approved posts` will be retrieved. Learn more about polymorphic relations [here](/docs/relations-schema-declaration#polymorphic-relations).

## ---

### One-to-one
Drizzle ORM provides you an API to define `one-to-one` relations between tables with the `defineRelations` function.

An example of a `one-to-one` relation between users and users, where a user can invite another (this example uses a self reference):

```typescript copy {10-17}
import { pgTable, text, integer } from 'drizzle-orm/pg-core';
import { defineRelations } from 'drizzle-orm';

export const users = pgTable('users', {
	id: integer().primaryKey(),
	name: text(),
	invitedBy: integer('invited_by'),
});

export const relations = defineRelations({ users }, (r) => ({
	users: {
		invitee: r.one.users({
			from: r.users.invitedBy,
			to: r.users.id,
		})
	}
}));
```

Another example would be a user having a profile information stored in separate table. In this case, because the foreign key is stored in the "profile_info" table, the user relation have neither fields or references. This tells Typescript that `user.profileInfo` is nullable:

```typescript copy {15-22}
import { pgTable, serial, text, integer, jsonb } from 'drizzle-orm/pg-core';
import { defineRelations } from 'drizzle-orm';

export const users = pgTable('users', {
	id: integer().primaryKey(),
	name: text(),
});

export const profileInfo = pgTable('profile_info', {
	id: serial().primaryKey(),
	userId: integer('user_id').references(() => users.id),
	metadata: jsonb(),
});

export const relations = defineRelations({ users, profileInfo }, (r) => ({
	users: {
		profileInfo: r.one.profileInfo({
			from: r.users.id,
			to: r.profileInfo.userId,
		})
	}
}));

const user = await db.query.users.findFirst({ with: { profileInfo: true } });
//____^? type { id: number, profileInfo: { ... } | null  }
```

### One-to-many
Drizzle ORM provides you an API to define `one-to-many` relations between tables with `defineRelations` function. 

Example of `one-to-many` relation between users and posts they've written:

```typescript copy {15-25}
import { pgTable, text, integer } from 'drizzle-orm/pg-core';
import { defineRelations } from 'drizzle-orm';

export const users = pgTable('users', {
	id: integer('id').primaryKey(),
	name: text('name'),
});

export const posts = pgTable('posts', {
	id: integer('id').primaryKey(),
	content: text('content'),
	authorId: integer('author_id'),
});

export const relations = defineRelations({ users, posts }, (r) => ({
  posts: {
    author: r.one.users({
      from: r.posts.authorId,
      to: r.users.id,
    }),
  },
  users: {
    posts: r.many.posts(),
  },
}));
```

Now lets add comments to the posts:
```typescript copy {9-14,22,27-32}
...

export const posts = pgTable('posts', {
	id: integer('id').primaryKey(),
	content: text('content'),
	authorId: integer('author_id'),
});

export const comments = pgTable("comments", {
  id: integer().primaryKey(),
  text: text(),
  authorId: integer("author_id"),
  postId: integer("post_id"),
});

export const relations = defineRelations({ users, posts, comments }, (r) => ({
  posts: {
    author: r.one.users({
      from: r.posts.authorId,
      to: r.users.id,
    }),
    comments: r.many.comments(),
  },
  users: {
    posts: r.many.posts(),
  },
  comments: {
    post: r.one.posts({
      from: r.comments.postId,
      to: r.posts.id,
    }),
  },
}));
```


### Many-to-many
Drizzle ORM provides you an API to define `many-to-many` relations between tables through so called `junction` or `join` tables,
they have to be explicitly defined and store associations between related tables.  

Example of `many-to-many` relation between users and groups we are using `through` to bypass junction table selection and directly select many `groups` for each `user`.
```typescript copy {27-39}
import { defineRelations } from 'drizzle-orm';
import { integer, pgTable, primaryKey, text } from 'drizzle-orm/pg-core';

export const users = pgTable('users', {
  id: integer().primaryKey(),
  name: text(),
});

export const groups = pgTable('groups', {
  id: integer().primaryKey(),
  name: text(),
});

export const usersToGroups = pgTable(
  'users_to_groups',
  {
    userId: integer('user_id')
      .notNull()
      .references(() => users.id),
    groupId: integer('group_id')
      .notNull()
      .references(() => groups.id),
  },
  (t) => [primaryKey({ columns: [t.userId, t.groupId] })],
);

export const relations = defineRelations({ users, groups, usersToGroups },
  (r) => ({
    users: {
      groups: r.many.groups({
        from: r.users.id.through(r.usersToGroups.userId),
        to: r.groups.id.through(r.usersToGroups.groupId),
      }),
    },
    groups: {
      participants: r.many.users(),
    },
  })
);
```

**Query example:**
```ts
const res = await db.query.users.findMany({
  with: { 
    groups: true 
  },
});

// response type
type Response = {
  id: number;
  name: string | null;
  groups: {
    id: number;
    name: string | null;
  }[];
}[];
```

### Predefined filters

Predefined `where` statements in Drizzle's relation definitions are a type of polymorphic relations implementation, but it's not fully it. Essentially, they allow you to
connect tables not only by selecting specific columns but also through custom `where` statements. Let's look at some examples:

We can define a relation between `groups` and `users` so that when querying group's users, we only retrieve those whose `verified` column is set to `true`
<CodeTabs items={["Relations", "Schema"]}>
<Section>
```ts
import { defineRelations } from "drizzle-orm";
import * as schema from './schema';

export const relations = defineRelations(schema,(r) => ({
    groups: {
      verifiedUsers: r.many.users({
        from: r.groups.id.through(r.usersToGroups.groupId),
        to: r.users.id.through(r.usersToGroups.userId),
        where: {
          verified: true,
        },
      }),
    },
  })
);

...

await db.query.groups.findMany({
    with: {
      verifiedUsers: true,
    },
});
```
</Section>
<Section>
```ts
import * as p from "drizzle-orm/pg-core";

export const users = p.pgTable("users", {
  id: p.integer().primaryKey(),
  name: p.text().notNull(),
  verified: p.boolean().notNull(),
});

export const groups = p.pgTable("groups", {
  id: p.integer().primaryKey(),
  title: p.text().notNull(),
});

export const usersToGroups = p.pgTable(
  "users_to_groups",
  {
    userId: p
      .integer("user_id")
      .notNull()
      .references(() => users.id, { onDelete: "cascade" }),
    groupId: p
      .integer("group_id")
      .notNull()
      .references(() => groups.id, { onDelete: "cascade" }),
  },
  (t) => [p.primaryKey({ columns: [t.groupId, t.userId] })]
);
```
</Section>
</CodeTabs>

<Callout type='warning'>
You can only specify filters on the target (to) table. So in this example, the where clause will only include columns from the `users` table since we are establishing a relation **TO** users

```ts {7}
export const relations = defineRelations(schema,(r) => ({
    groups: {
      verifiedUsers: r.many.users({
        from: r.groups.id.through(r.usersToGroups.groupId),
        to: r.users.id.through(r.usersToGroups.userId),
        where: {
          verified: true,
        },
      }),
    },
  })
);
```
</Callout>

## ---

### Relations Parts

In a case you need to separate relations config into several parts you can use `defineRelationsPart` helpers

```ts
import { defineRelations, defineRelationsPart } from 'drizzle-orm';
import * as schema from "./schema";

export const relations = defineRelations(schema, (r) => ({
  users: {
    invitee: r.one.users({
      from: r.users.invitedBy,
      to: r.users.id,
    }),
    posts: r.many.posts(),
  }
}));

export const part = defineRelationsPart(schema, (r) => ({
  posts: {
    author: r.one.users({
      from: r.posts.authorId,
      to: r.users.id,
    }),
  }
}));
```

and then you can provide it to the db instance

```ts
const db = drizzle(process.env.DB_URL, { relations: { ...relations, ...part } })
```

<Callout type='warning'>
There are a few rules you would need to follow to make sure it `defineRelationsParts` works as expected

**Rule 1**: If you specify reltions with parts, when passing it to drizzle db function you would need to specify it in the right order(main relations goes first)
```ts
// ✅
const db = drizzle(process.env.DB_URL, { relations: { ...relations, ...part } })

// ❌
const db = drizzle(process.env.DB_URL, { relations: { ...part, ...relations } })
```

<Callout collapsed="Why it's important?">
Even if there will be no type or runtime error, this is how "..." works with objects. As long as main relation 
recursively infer all tables names, so it can be available in autocomplete. Here is an example:

```ts
export const relations = defineRelations(schema, (r) => ({
  users: {
    invitee: r.one.users({
      from: r.users.invitedBy,
      to: r.users.id,
    }),
    posts: r.many.posts(),
  }
}));

export const part = defineRelationsPart(schema, (r) => ({
  posts: {
    author: r.one.users({
      from: r.posts.authorId,
      to: r.users.id,
    }),
  }
}));
```

Here `relations` and `part` can be represented and this object:
```json
// relations
{
  "users": {"invitee": {...}, "posts": {...}},
  // added here, so all tables from schema will exist in autocomplete
  "posts": {}
}

// part
{
  "posts": {"author": {...}}
}
```

Having `{ ...relations, ...part }` will result in 
```json
{
  "users": {"invitee": {...}, "posts": {...}},
  "posts": {"author": {...}}
}
```

and having `{ ...relations, ...part }` will result in
```json
{
  "users": {"invitee": {...}, "posts": {...}},
  // As you can see in the final object, posts relations information will be lost
  "posts": {}
}
```

</Callout>

**Rule 2**: You should have min relations, so drizzle can infer all of the table for autocomplete. If you want to have only parts, then 
one of your parts should be empty, like this:

```ts
export const mainPart = defineRelationsPart(schema);
```

In this case, all tables will be inferred correctly, and you'll have complete information about your schema
</Callout>

## ---

### Performance

When working with relations in Drizzle ORM, especially in applications with 
significant data or complex queries, optimizing database performance is crucial.  
Indexes play a vital role in speeding up data retrieval, particularly when querying 
related data. This section outlines recommended indexing strategies for each type 
of relationship defined using Drizzle ORM.

##### One-to-one Relationships

In a one-to-one relationship, like the "user invites user" example or the
"user has profile info" example, the key performance consideration is efficient joining 
of the related tables.

<Callout>
For optimal performance in one-to-one relationships, you should create an index 
on the foreign key column in the table that is being referenced 
(the "target" table in the relation).
</Callout>

<Callout collapsed='Why it is important'>
When you query data with related one-to-one information, Drizzle performs a JOIN operation. An index on the foreign key column allows the database to quickly 
locate the related row in the target table, significantly speeding up the join process.
</Callout>

**Example:**
```typescript
import * as p from 'drizzle-orm/pg-core';
import { defineRelations } from 'drizzle-orm';

export const users = p.pgTable('users', {
	id: p.integer().primaryKey(),
	name: p.text(),
});

export const profileInfo = p.pgTable('profile_info', {
	id: p.integer().primaryKey(),
	userId: p.integer('user_id').references(() => users.id),
	metadata: p.jsonb(),
});

export const relations = defineRelations({ users, profileInfo }, (r) => ({
	users: {
		profileInfo: r.one.profileInfo({
			from: r.users.id,
			to: r.profileInfo.userId,
		})
	}
}));
```

To optimize queries fetching user data along with their profile information, 
you should create an index on the `userId` column in the `profile_info` table.

```typescript {13-15,21}
import * as p from 'drizzle-orm/pg-core';
import { defineRelations } from 'drizzle-orm';

export const users = p.pgTable('users', {
	id: p.integer().primaryKey(),
	name: p.text(),
});

export const profileInfo = pgTable('profile_info', {
	id: p.integer().primaryKey(),
	userId: p.integer('user_id').references(() => users.id),
	metadata: p.jsonb(),
}, (table) => [
  p.index('profile_info_user_id_idx').on(table.userId)
]);

export const relations = defineRelations({ users, profileInfo }, (r) => ({
	users: {
		profileInfo: r.one.profileInfo({
			from: r.users.id,
			to: r.profileInfo.userId,
		})
	}
}));
```
```sql
CREATE INDEX idx_profile_info_user_id ON profile_info (user_id);
```

#### One-to-many Relationships

Similar to one-to-one relationships, one-to-many relations benefit significantly 
from indexing to optimize join operations. Consider the "users and posts" example where one user can have many posts.

<Callout>
For one-to-many relationships, create an index on the foreign key column in the table that represents the "many" side of the relationship (the table with the foreign key referencing the "one" side).
</Callout>

<Callout collapsed='Why it is important'>
When you fetch a user with their posts or posts with their authors, joins are performed.
Indexing the foreign key (`authorId` in `posts` table) allows the database to efficiently 
retrieve all posts associated with a given user or quickly find the author of a post.
</Callout>

**Example:**
```typescript
import * as p from "drizzle-orm/pg-core";
import { defineRelations } from 'drizzle-orm';

export const users = p.pgTable('users', {
	id: p.integer().primaryKey(),
	name: p.text(),
});

export const posts = p.pgTable('posts', {
	id: p.integer().primaryKey(),
	content: p.text(),
	authorId: p.integer('author_id'),
});

export const relations = defineRelations({ users, posts }, (r) => ({
  posts: {
    author: r.one.users({
      from: r.posts.authorId,
      to: r.users.id,
    }),
  },
  users: {
    posts: r.many.posts(),
  },
}));
```

To optimize queries involving users and their posts, create an index on the `authorId` column in the `posts` table.

```typescript {13-15}
import * as p from "drizzle-orm/pg-core";
import { defineRelations } from 'drizzle-orm';

export const users = p.pgTable('users', {
	id: p.integer().primaryKey(),
	name: p.text(),
});

export const posts = p.pgTable('posts', {
	id: p.integer().primaryKey(),
	content: p.text(),
	authorId: p.integer('author_id'),
}, (t) => [
  index('posts_author_id_idx').on(table.authorId)
]);

export const relations = defineRelations({ users, posts }, (r) => ({
  posts: {
    author: r.one.users({
      from: r.posts.authorId,
      to: r.users.id,
    }),
  },
  users: {
    posts: r.many.posts(),
  },
}));
```
```sql
CREATE INDEX idx_posts_author_id ON posts (author_id);
```

#### Many-to-many Relationships

Many-to-many relationships, implemented using junction tables, require a slightly 
more nuanced indexing strategy to ensure optimal query performance. 
Consider the "users and groups" example with the `usersToGroups` junction table.

<Callout>
For many-to-many relationships, it is generally recommended to create the following 
indexes on the junction table:
1.  **Index on each foreign key column individually:** This optimizes queries that 
filter or join based on a single side of the relationship 
(e.g., finding all groups for a user OR all users in a group).
2.  **Composite index on both foreign key columns together:** This is crucial for 
efficiently resolving the many-to-many relationship itself. It speeds up queries that need to find the connections between both entities.
</Callout>

<Callout collapsed='Why it is important'>
When querying many-to-many relations, especially when using `through` in Drizzle ORM, the database needs to efficiently navigate the junction table.

- Indexes on individual foreign key columns (`userId`, `groupId` in `usersToGroups`) help when you are querying from one side to find the other (e.g., "find groups for a user").
- The composite index on `(userId, groupId)` in `usersToGroups` is particularly important for quickly finding all relationships defined in the junction table. This is used when Drizzle ORM resolves the `many-to-many` relation to fetch related entities.
</Callout>

**Example:**

In the "users and groups" example, the `usersToGroups` junction table connects `users` and `groups`.

```typescript
import { defineRelations } from 'drizzle-orm';
import * as p from 'drizzle-orm/pg-core';

export const users = p.pgTable('users', {
  id: p.integer().primaryKey(),
  name: p.text(),
});

export const groups = p.pgTable('groups', {
  id: p.integer().primaryKey(),
  name: p.text(),
});

export const usersToGroups = p.pgTable(
  'users_to_groups',
  {
    userId: p.integer('user_id')
      .notNull()
      .references(() => users.id),
    groupId: p.integer('group_id')
      .notNull()
      .references(() => groups.id),
  },
  (t) => [p.primaryKey({ columns: [t.userId, t.groupId] })],
);

export const relations = defineRelations({ users, groups, usersToGroups },
  (r) => ({
    users: {
      groups: r.many.groups({
        from: r.users.id.through(r.usersToGroups.userId),
        to: r.groups.id.through(r.usersToGroups.groupId),
      }),
    },
    groups: {
      participants: r.many.users(),
    },
  })
);
```

To optimize queries for users and groups, create indexes on `usersToGroups` table as follows:

```typescript {26-28}
import { defineRelations } from 'drizzle-orm';
import * as p from 'drizzle-orm/pg-core';

export const users = p.pgTable('users', {
  id: p.integer().primaryKey(),
  name: p.text(),
});

export const groups = p.pgTable('groups', {
  id: p.integer().primaryKey(),
  name: p.text(),
});

export const usersToGroups = p.pgTable(
  'users_to_groups',
  {
    userId: p.integer('user_id')
      .notNull()
      .references(() => users.id),
    groupId: p.integer('group_id')
      .notNull()
      .references(() => groups.id),
  },
  (t) => [
    p.primaryKey({ columns: [t.userId, t.groupId] }),
    p.index('users_to_groups_user_id_idx').on(table.userId),
    p.index('users_to_groups_group_id_idx').on(table.groupId),
    p.index('users_to_groups_composite_idx').on(table.userId, table.groupId),
  ],
);

export const relations = defineRelations({ users, groups, usersToGroups },
  (r) => ({
    users: {
      groups: r.many.groups({
        from: r.users.id.through(r.usersToGroups.userId),
        to: r.groups.id.through(r.usersToGroups.groupId),
      }),
    },
    groups: {
      participants: r.many.users(),
    },
  })
);
```
```sql
CREATE INDEX idx_users_to_groups_user_id ON users_to_groups (user_id);
CREATE INDEX idx_users_to_groups_group_id ON users_to_groups (group_id);
CREATE INDEX idx_users_to_groups_composite ON users_to_groups (userId, groupId);
```

By applying these indexing strategies, you can significantly improve the performance of your Drizzle ORM applications when working with relational data, especially as your data volume grows and your queries become more complex. Remember to choose the indexes that best suit your specific query patterns and application needs.

## ---

### Foreign keys

You might've noticed that `relations` look similar to foreign keys — they even have a `references` property. So what's the difference?

While foreign keys serve a similar purpose, defining relations between tables, they work on a different level compared to `relations`.

Foreign keys are a database level constraint, they are checked on every `insert`/`update`/`delete` operation and throw an error if a constraint is violated.
On the other hand, `relations` are a higher level abstraction, they are used to define relations between tables on the application level only.
They do not affect the database schema in any way and do not create foreign keys implicitly.

What this means is `relations` and foreign keys can be used together, but they are not dependent on each other.
You can define `relations` without using foreign keys (and vice versa), which allows them to be used with databases that do not support foreign keys.

The following two examples will work exactly the same in terms of querying the data using Drizzle relational queries.

<CodeTabs items={["schema1.ts", "schema2.ts"]}>
<CodeTab>
```ts {15}
export const users = p.pgTable("users", {
  id: p.integer().primaryKey(),
  name: p.text(),
});

export const profileInfo = p.pgTable("profile_info", {
  id: p.integer().primaryKey(),
  userId: p.integer("user_id"),
  metadata: p.jsonb(),
});

export const relations = defineRelations({ users, profileInfo }, (r) => ({
  users: {
    profileInfo: r.one.profileInfo({
      from: r.users.id,
      to: r.profileInfo.userId,
    }),
  },
}));
```
</CodeTab>
<CodeTab>
```ts {15}
export const users = p.pgTable("users", {
  id: p.integer().primaryKey(),
  name: p.text(),
});

export const profileInfo = p.pgTable("profile_info", {
  id: p.integer().primaryKey(),
  userId: p.integer("user_id").references(() => users.id),
  metadata: p.jsonb(),
});

export const relations = defineRelations({ users, profileInfo }, (r) => ({
  users: {
    profileInfo: r.one.profileInfo({
      from: r.users.id,
      to: r.profileInfo.userId,
    }),
  },
}));
```
</CodeTab>
</CodeTabs>

### Disambiguating relations

Drizzle also provides the `alias` option as a way to disambiguate
relations when you define multiple of them between the same two tables. For
example, if you define a `posts` table that has the `author` and `reviewer`
relations.

```ts {19,22,29,34}
import { pgTable, integer, text } from 'drizzle-orm/pg-core';
import { defineRelations } from 'drizzle-orm';
 
export const users = pgTable('users', {
	id: integer('id').primaryKey(),
	name: text('name'),
});

export const posts = pgTable('posts', {
	id: integer('id').primaryKey(),
	content: text('content'),
	authorId: integer('author_id'),
	reviewerId: integer('reviewer_id'),
});
 
export const relations = defineRelations({ users, posts }, (r) => ({
  users: {
    posts: r.many.posts({
      alias: "author",
    }),
    reviewedPosts: r.many.posts({
      alias: "reviewer",
    }),
  },
  posts: {
    author: r.one.users({
      from: r.posts.authorId,
      to: r.users.id,
      alias: "author",
    }),
    reviewer: r.one.users({
      from: r.posts.authorId,
      to: r.users.id,
      alias: "reviewer",
    }),
  },
}));
```


Source: https://orm.drizzle.team/docs/singlestore/rqb-v2

import Npm from '@mdx/Npm.astro';
import Callout from '@mdx/Callout.astro';
import CodeTabs from '@mdx/CodeTabs.astro';
import CodeTab from '@mdx/CodeTab.astro';
import Section from '@mdx/Section.astro';

# Drizzle Queries

<Callout type='error'>
This page explains concepts available on drizzle versions `1.0.0-beta.1` and higher.
</Callout>

<Npm>
drizzle-orm@rc
drizzle-kit@rc -D
</Npm>

<br/>

Drizzle ORM is designed to be a thin typed layer on top of SQL. 
We truly believe we've designed the best way to operate an SQL database from TypeScript and it's time to make it better.  
  
Relational queries are meant to provide you with a great developer experience for querying 
nested relational data from an SQL database, avoiding multiple joins and complex data mappings.  

It is an extension to the existing schema definition and query builder. 
You can opt-in to use it based on your needs. 
We've made sure you have both the best-in-class developer experience and performance.  

<CodeTabs items={["index.ts", "schema.ts"]}>
	<CodeTab>
	```typescript copy /schema/3
	import { relations } from './schema';
	import { drizzle } from 'drizzle-orm/...';

	const db = drizzle({ relations });

	const result = await db.query.users.findMany({
		with: {
			posts: true			
		},
	});
	```

	```ts
	[{
		id: 10,
		name: "Dan",
		posts: [
			{
				id: 1,
				content: "SQL is awesome",
				authorId: 10,
			},
			{
				id: 2,
				content: "But check relational queries",
				authorId: 10,
			}
		]
	}]
	```
	</CodeTab>

	```typescript {15-25} copy
    import { defineRelations } from "drizzle-orm";
    import * as t from "drizzle-orm/singlestore-core";
    
    export const posts = t.singlestoreTable("posts", {
      id: t.int().primaryKey().autoincrement(),
      content: t.text().notNull(),
      authorId: t.int("author_id").notNull(),
    });
    
    export const users = t.singlestoreTable("users", {
      id: t.int().primaryKey().autoincrement(),
      name: t.text().notNull(),
    });
    
    export const relations = defineRelations({ users, posts }, (r) => ({
      posts: {
        author: r.one.users({
          from: r.posts.authorId,
          to: r.users.id,
        }),
      },
      users: {
        posts: r.many.users(),
      },
    }));
	```
</CodeTabs>

Relational queries are an extension to Drizzle's original **[query builder](/docs/singlestore/select)**.
You need to provide all `tables` and `relations` from your schema file/files upon `drizzle()` 
initialization and then just use the `db.query` API.
<Callout type="info" emoji="ℹ️">
	`drizzle` import path depends on the **[database driver](/docs/singlestore/connect-overview)** you're using.
</Callout>
<CodeTabs items={["index.ts", "schema.ts", "relations.ts"]}>
<CodeTab>
```ts
import { relations } from './relations';
import { drizzle } from 'drizzle-orm/...';

const db = drizzle({ relations });

await db.query.users.findMany(...);
```
</CodeTab>
```typescript copy
import { type AnyMySqlColumn, boolean, int, singlestoreTable, primaryKey, text, timestamp } from 'drizzle-orm/singlestore-core';

export const users = singlestoreTable('users', {
	id: int().primaryKey().autoincrement(),
	name: text().notNull(),
	invitedBy: int('invited_by').references((): AnyMySqlColumn => users.id),
});

export const groups = singlestoreTable('groups', {
	id: int().primaryKey().autoincrement(),
	name: text().notNull(),
	description: text(),
});

export const usersToGroups = singlestoreTable('users_to_groups', {
	id: int().primaryKey().autoincrement(),
	userId: int('user_id').notNull().references(() => users.id),
	groupId: int('group_id').notNull().references(() => groups.id),
}, (t) => [
	primaryKey(t.userId, t.groupId)
]);

export const posts = singlestoreTable('posts', {
	id: int().primaryKey().autoincrement(),
	content: text().notNull(),
	authorId: int('author_id').references(() => users.id),
	createdAt: timestamp('created_at').notNull().defaultNow(),
});

export const comments = singlestoreTable('comments', {
	id: int().primaryKey().autoincrement(),
	content: text().notNull(),
	creator: int().references(() => users.id),
	postId: int('post_id').references(() => posts.id),
	createdAt: timestamp('created_at').notNull().defaultNow(),
});

export const commentLikes = singlestoreTable('comment_likes', {
	id: int().primaryKey().autoincrement(),
	creator: int().references(() => users.id),
	commentId: int('comment_id').references(() => comments.id),
	createdAt: timestamp('created_at').notNull().defaultNow(),
});
```
```typescript copy
import { defineRelations } from 'drizzle-orm';
import * as schema from './schema';

export const relations = defineRelations(schema, (r) => ({
    users: {
      invitee: r.one.users({
        from: r.users.invitedBy,
        to: r.users.id,
      }),
      groups: r.many.groups({
        from: r.users.id.through(r.usersToGroups.userId),
        to: r.groups.id.through(r.usersToGroups.groupId),
      }),
      posts: r.many.posts(),
    },
    groups: {
      users: r.many.users(),
    },
    posts: {
      author: r.one.users({
        from: r.posts.authorId,
        to: r.users.id,
      }),
      comments: r.many.comments(),
    },
    comments: {
      post: r.one.posts({
        from: r.comments.postId,
        to: r.posts.id,
      }),
      author: r.one.users({
        from: r.comments.creator,
        to: r.users.id,
      }),
      likes: r.many.commentLikes(),
    },
    commentLikes: {
      comment: r.one.comments({
        from: r.commentLikes.commentId,
        to: r.comments.id,
      }),
      author: r.one.users({
        from: r.commentLikes.creator,
        to: r.users.id,
      }),
    },
  })
);
```
</CodeTabs>

Drizzle provides `.findMany()` and `.findFirst()` APIs.
### Find many
<Section>
```typescript copy
const users = await db.query.users.findMany();
```
```ts
// result type
const result: {
	id: number;
	name: string;
	verified: boolean;
	invitedBy: number | null;
}[];
```
</Section>

### Find first
<Callout>
  `.findFirst()` will add `limit 1` to the query.
</Callout>
<Section>
```typescript copy
const user = await db.query.users.findFirst();
```
```ts
// result type
const result: {
	id: number;
	name: string;
	verified: boolean;
	invitedBy: number | null;
};
```
</Section>

### Include relations

`With` operator lets you combine data from multiple related tables and properly aggregate results.

**Getting all posts with comments:**
```typescript copy
const posts = await db.query.posts.findMany({
	with: {
		comments: true,
	},
});
```

**Getting first post with comments:**
```typescript copy
const post = await db.query.posts.findFirst({
	with: {
		comments: true,
	},
});
```

You can chain nested with statements as much as necessary.  
For any nested `with` queries Drizzle will infer types using [Core Type API](/docs/singlestore/goodies#type-api).
  
**Get all users with posts. Each post should contain a list of comments:**
```typescript copy
const users = await db.query.users.findMany({
	with: {
		posts: {
			with: {
				comments: true,
			},
		},
	},
});
```

### Partial fields select
`columns` parameter lets you include or omit columns you want to get from the database.

<Callout type="info" emoji="ℹ️">
  Drizzle performs partial selects on the query level, no additional data is transferred from the database.

  Keep in mind that **a single SQL statement is outputted by Drizzle.**
</Callout>

**Get all posts with just `id`, `content` and include `comments`:**
```typescript copy
const posts = await db.query.posts.findMany({
	columns: {
		id: true,
		content: true,
	},
	with: {
		comments: true,
	}
});
```

**Get all posts without `content`:**
```typescript copy
const posts = await db.query.posts.findMany({
	columns: {
		content: false,
	},
});
```

<Callout type="info" emoji="ℹ️">
When both `true` and `false` select options are present, all `false` options are ignored.
</Callout>

If you include the `name` field and exclude the `id` field, `id` exclusion will be redundant, 
all fields apart from `name` would be excluded anyways.  
  
**Exclude and Include fields in the same query:**
<Section>
```typescript copy
const users = await db.query.users.findMany({
	columns: {
		name: true,
		id: false //ignored
	},
});
```
```ts
// result type
const users: {
	name: string;
};
```
</Section>

**Only include columns from nested relations:**
<Section>
```typescript copy
const res = await db.query.users.findMany({
	columns: {},
	with: {
		posts: true
	}
});
```
```ts
// result type
const res: {
	posts: {
		id: number,
		text: string
	}
}[];
```
</Section>

### Nested partial fields select
Just like with **[`partial select`](#partial-select)**, you can include or exclude columns of nested relations:
```typescript copy
const posts = await db.query.posts.findMany({
	columns: {
		id: true,
		content: true,
	},
	with: {
		comments: {
			columns: {
				authorId: false
			}
		}
	}
});
```

### Select filters
Just like in our SQL-like query builder, 
relational queries API lets you define filters and conditions with the list of our **[`operators`](/docs/singlestore/operators)**.  

You can either import them from `drizzle-orm` or use from the callback syntax:
<Section>
```typescript copy
const users = await db.query.users.findMany({
	where: {
		id: 1
	}
});
```
```sql
select * from users where id = 1
```
</Section>

Find post with `id=1` and comments that were created before particular date:
```typescript copy
await db.query.posts.findMany({
  where: {
    id: 1,
  },
  with: {
    comments: {
      where: {
        createdAt: { lt: new Date() },
      },
    },
  },
});
```

**List of all filter operators**
```ts
where: {
    OR: [],
    AND: [],
    NOT: {},
    RAW: (table) => sql`${table.id} = 1`,

    // filter by relations
    [relation]: {},

	  // filter by columns
    [column]: {
      OR: [],
      AND: [],
      NOT: {},
      eq: 1,
      ne: 1,
      gt: 1,
      gte: 1,
      lt: 1,
      lte: 1,
      in: [1],
      notIn: [1],
      like: "",
      notLike: "",
      isNull: true,
      isNotNull: true,
    },
},
```

**Examples**
<CodeTabs items={["simple eq", "using AND", "using OR", "using NOT", "complex example using RAW"]}>
<CodeTab>
```ts
const response = db.query.users.findMany({
  where: {
    age: 15,
  },
});
```
```sql {3}
select `users`.`id` as `id`, `users`.`name` as `name`
from `users` 
where (`users`.`age` = 15)
```
</CodeTab>
<CodeTab>
```ts
const response = db.query.users.findMany({
  where: {
    age: 15,
    name: 'John'
  },
});
```
```sql {3}
select `users`.`id` as `id`, `users`.`name` as `name`
from `users` 
where (`users`.`age` = 15 and `users`.`name` = 'John')
```
</CodeTab>
<CodeTab>
```ts
const response = await db.query.users.findMany({
  where: {
    OR: [
      {
        id: {
          gt: 10,
        },
      },
	  {
		name: {
          like: "John%",
        },
	  }
    ],
  },
});
```
```sql {3}
select `users`.`id` as `id`, `users`.`name` as `name` 
from `users` 
where (`users`.`id` > 10 or `users`.`name` like 'John%')
```
</CodeTab>
<CodeTab>
```ts
const response = db.query.users.findMany({
  where: {
    NOT: {
      id: {
        gt: 10,
      },
    },
    name: {
      like: "John%",
    },
  },
});
```
```sql {3}
select `users`.`id` as `id`, `users`.`name` as `name` 
from `users` 
where (not `users`.`id` > 10 and `users`.`name` like 'John%')
```
</CodeTab>
<CodeTab>
```ts
// schema.ts
import { int, json, singlestoreTable, text, timestamp } from "drizzle-orm/singlestore-core";

export const users = singlestoreTable("users", {
  id: int("id").primaryKey().autoincrement(),
  name: text("name"),
  email: text("email").notNull(),
  age: int("age"),
  createdAt: timestamp("created_at").defaultNow(),
  lastLogin: timestamp("last_login"),
  subscriptionEnd: timestamp("subscription_end"),
  lastActivity: timestamp("last_activity"),
  preferences: json("preferences"),        // JSON column for user settings/preferences
  interests: text("interests"),            // Comma-separated user interests
});
```
```ts
const response = db.query.users.findMany({
  where: {
    AND: [
      {
        OR: [
          { RAW: (table) => sql`LOWER(${table.name}) LIKE 'john%'` },
          { name: { like: "jane%" } },
        ],
      },
      {
        OR: [
          { RAW: (table) => sql`JSON_EXTRACT(${table.preferences}, '$.theme') = '"dark"'` },
          { RAW: (table) => sql`JSON_EXTRACT(${table.preferences}, '$.theme') IS NULL` },
        ],
      },
      { RAW: (table) => sql`${table.age} BETWEEN 25 AND 35` },
    ],
  },
});
```
```sql
select `d0`.`id` as `id`, `d0`.`name` as `name`, 
`d0`.`email` as `email`, `d0`.`age` as `age`, 
`d0`.`created_at` as `createdAt`, `d0`.`last_login` as `lastLogin`, 
`d0`.`subscription_end` as `subscriptionEnd`, `d0`.`last_activity` as `lastActivity`, 
`d0`.`preferences` as `preferences`, `d0`.`interests` as `interests` 
from `users` as `d0` 
where ((LOWER(`d0`.`name`) LIKE 'john%' or `d0`.`name` like 'jane%') 
and (JSON_EXTRACT(`d0`.`preferences`, '$.theme') = '"dark"' or JSON_EXTRACT(`d0`.`preferences`, '$.theme') IS NULL) 
and `d0`.`age` BETWEEN 25 AND 35)
```
</CodeTab>
</CodeTabs>

### Relations Filters

With Drizzle Relations, you can filter not only by the table you're querying but also by any table you include in the query.

**Example:** Get all `users` whose ID>10 and who have at least one post with content starting with "M"
```ts
const usersWithPosts = await db.query.usersTable.findMany({
  where: {
    id: {
      gt: 10
    },
    posts: {
      content: {
        like: 'M%'
      }
    }
  },
});
```

**Example:** Get all `users` with posts, only if user has at least 1 post
```ts
const response = db.query.users.findMany({
  with: {
    posts: true,
  },
  where: {
    posts: true,
  },
});
```

### Limit & Offset
Drizzle ORM provides `limit` & `offset` API for queries and for the nested entities.
  
**Find 5 posts:**
```typescript copy
await db.query.posts.findMany({
	limit: 5,
});
```

**Find posts and get 3 comments at most:**
```typescript copy
await db.query.posts.findMany({
	with: {
		comments: {
			limit: 3,
		},
	},
});
```

<Callout type="warning" emoji="⚠️">
  `offset` now can be used in with tables as well!
</Callout>
```typescript 
await db.query.posts.findMany({
	limit: 5,
	offset: 2, // correct ✅
	with: {
		comments: {
			offset: 3, // correct ✅
			limit: 3,
		},
	},
});
```

Find posts with comments from the 5th to the 10th post:
```typescript copy
await db.query.posts.findMany({
	with: {
		comments: true,
	},
  limit: 5,
  offset: 5,
});
```

### Order By
Drizzle provides API for ordering in the relational query builder.  

You can use same ordering **[core API](/docs/singlestore/select#order-by)** or use
`order by` operator from the callback with no imports.  

<Callout title='important'>
When you use multiple `orderBy` statements in the same table, they will be included in the query in the same order in which you added them
</Callout>

<Section>
```typescript copy
await db.query.posts.findMany({
  orderBy: {
    id: "asc",
  },
});
```
</Section>

**Order by `asc` + `desc`:**
```typescript copy
  await db.query.posts.findMany({
    orderBy: { id: "asc" },
    with: {
      comments: {
        orderBy: { id: "desc" },
      },
    },
  });
```

You can also use custom `sql` in order by statement:

```typescript copy
await db.query.posts.findMany({
  orderBy: (t) => sql`${t.id} asc`,
  with: {
    comments: {
      orderBy: (t, { desc }) => desc(t.id),
    },
  },
});
```

### Include custom fields
Relational query API lets you add custom additional fields. 
It's useful when you need to retrieve data and apply additional functions to it.
<Callout type="warning" emoji="⚠️">
	As of now aggregations are not supported in `extras`, please use **[`core queries`](/docs/singlestore/select)** for that.
</Callout>

<Section>
```typescript copy {5}
import { sql } from 'drizzle-orm';

await db.query.users.findMany({
	extras: {
		loweredName: sql`lower(${users.name})`,
	},
})
```
```typescript copy {3}
await db.query.users.findMany({
	extras: {
		loweredName: (users, { sql }) => sql`lower(${users.name})`,
	},
})
```
</Section>

`lowerName` as a key will be included to all fields in returned object.

<Callout type="warning" emoji="⚠️">
  If you will specify `.as("<alias>")` for any extras field - drizzle will ignore it
</Callout>

To retrieve all users with groups, but with the fullName field included (which is a concatenation of firstName and lastName), 
you can use the following query with the Drizzle relational query builder.

<Section>
```typescript copy
const res = await db.query.users.findMany({
	extras: {
		fullName: (users, { sql }) => sql<string>`concat(${users.name}, " ", ${users.name})`,
	},
	with: {
		usersToGroups: {
			with: {
				group: true,
			},
		},
	},
});
```
```ts
// result type
const res: {
	id: number;
	name: string;
	verified: boolean;
	invitedBy: number | null;
	fullName: string;
	usersToGroups: {
			group: {
					id: number;
					name: string;
					description: string | null;
			};
	}[];
}[];

```
</Section>

To retrieve all posts with comments and add an additional field to calculate the size of the post content and the size of each comment content:
<Section>
```typescript copy
const res = await db.query.posts.findMany({
	extras: {
		contentLength: (table, { sql }) => sql<number>`length(${table.content})`,
	},
	with: {
		comments: {
			extras: {
				commentSize: (table, { sql }) => sql<number>`length(${table.content})`,
			},
		},
	},
});
```
```ts
// result type
const res: {
	id: number;
	createdAt: Date;
	content: string;
	authorId: number | null;
	contentLength: number;
	comments: {
			id: number;
			createdAt: Date;
			content: string;
			creator: number | null;
			postId: number | null;
			commentSize: number;
	}[];
};
```
</Section>

### Include subqueries

You can also use subqueries within Relational Queries to leverage the power of custom SQL syntax

**Get users with posts and total posts count for each user**
```ts
import { posts } from './schema';
import { eq } from 'drizzle-orm';

await db.query.users.findMany({
  with: {
    posts: true
  },
  extras: {
    totalPostsCount: (table) => db.$count(posts, eq(posts.authorId, table.id)),
  }
});
```
```sql
select `d0`.`id` as `id`, `d0`.`name` as `name`,
((select coalesce(json_arrayagg(json_object('id', `d1`.`id`, 'content', `d1`.`content`, 'authorId', `d1`.`author_id`)), json_array())
  from `posts` as `d1` where `d0`.`id` = `d1`.`author_id`)) as `posts`,
((select count(*) from `posts` where `posts`.`author_id` = `d0`.`id`)) as `totalPostsCount`
from `users` as `d0`
```

### Prepared statements
Prepared statements are designed to massively improve query performance — [see here.](/docs/singlestore/perf-queries)

In this section, you can learn how to define placeholders and execute prepared statements 
using the Drizzle relational query builder.


Source: https://orm.drizzle.team/docs/singlestore/rqb

import Callout from '@mdx/Callout.astro';
import CodeTabs from '@mdx/CodeTabs.astro';
import CodeTab from '@mdx/CodeTab.astro';
import Section from '@mdx/Section.astro';

# Drizzle Queries

Drizzle ORM is designed to be a thin typed layer on top of SQL. 
We truly believe we've designed the best way to operate an SQL database from TypeScript and it's time to make it better.  
  
Relational queries are meant to provide you with a great developer experience for querying 
nested relational data from an SQL database, avoiding multiple joins and complex data mappings.  

It is an extension to the existing schema definition and query builder. 
You can opt-in to use it based on your needs. 
We've made sure you have both the best-in-class developer experience and performance.  

<CodeTabs items={["index.ts", "schema.ts"]}>
	<CodeTab>
	```typescript copy /schema/3
	import * as schema from './schema';
	import { drizzle } from 'drizzle-orm/...';

	const db = drizzle({ schema });

	const result = await db._query.users.findMany({
		with: {
			posts: true			
		},
	});
	```

	```ts
	[{
		id: 10,
		name: "Dan",
		posts: [
			{
				id: 1,
				content: "SQL is awesome",
				authorId: 10,
			},
			{
				id: 2,
				content: "But check relational queries",
				authorId: 10,
			}
		]
	}]
	```
	</CodeTab>

	```typescript copy
	import { int, singlestoreTable, text } from 'drizzle-orm/singlestore-core';
	import { relations } from 'drizzle-orm';

	export const users = singlestoreTable('users', {
		id: int('id').primaryKey().autoincrement(),
		name: text('name').notNull(),
	});

	export const usersRelations = relations(users, ({ many }) => ({
		posts: many(posts),
	}));

	export const posts = singlestoreTable('posts', {
		id: int('id').primaryKey().autoincrement(),
		content: text('content').notNull(),
		authorId: int('author_id').notNull(),
	});

	export const postsRelations = relations(posts, ({ one }) => ({
		author: one(users, { fields: [posts.authorId], references: [users.id] }),
	}));
	```
</CodeTabs>

⚠️ If you have SQL schema declared in multiple files you can do it like that
<CodeTabs items={["index.ts", "schema1.ts", "schema2.ts"]}>
	```typescript copy /schema/3
	import * as schema1 from './schema1';
	import * as schema2 from './schema2';
	import { drizzle } from 'drizzle-orm/...';

	const db = drizzle({ schema: { ...schema1, ...schema2 } });

	const result = await db._query.users.findMany({
		with: {
			posts: true			
		},
	});
	```
	
	```ts
	// schema declaration in the first file
	```
	```ts
	// schema declaration in the second file
	```
</CodeTabs>

## Querying
Relational queries are an extension to Drizzle's original **[query builder](/docs/singlestore/select)**.
You need to provide all `tables` and `relations` from your schema file/files upon `drizzle()` 
initialization and then just use the `db._query` API.
<Callout type="info" emoji="ℹ️">
	`drizzle` import path depends on the **[database driver](/docs/singlestore/connect-overview)** you're using.
</Callout>
<CodeTabs items={["index.ts", "schema.ts"]}>
<CodeTab>
```ts
import * as schema from './schema';
import { drizzle } from 'drizzle-orm/...';

const db = drizzle({ schema });

await db._query.users.findMany(...);
```
```ts
// if you have schema in multiple files
import * as schema1 from './schema1';
import * as schema2 from './schema2';
import { drizzle } from 'drizzle-orm/...';

const db = drizzle({ schema: { ...schema1, ...schema2 } });

await db._query.users.findMany(...);
```
</CodeTab>
```typescript copy
	import { type AnyMySqlColumn, boolean, int, singlestoreTable, primaryKey, text, timestamp } from 'drizzle-orm/singlestore-core';

	import { relations } from 'drizzle-orm';

	export const users = singlestoreTable('users', {
		id: int('id').primaryKey().autoincrement(),
		name: text('name').notNull(),
		verified: boolean('verified').notNull(),
		invitedBy: int('invited_by').references((): AnyMySqlColumn => users.id),
	});

	export const usersRelations = relations(users, ({ one, many }) => ({
		invitee: one(users, { fields: [users.invitedBy], references: [users.id] }),
		usersToGroups: many(usersToGroups),
		posts: many(posts),
	}));

	export const groups = singlestoreTable('groups', {
		id: int('id').primaryKey().autoincrement(),
		name: text('name').notNull(),
		description: text('description'),
	});

	export const groupsRelations = relations(groups, ({ many }) => ({
		usersToGroups: many(usersToGroups),
	}));

	export const usersToGroups = singlestoreTable('users_to_groups', {
		id: int('id').primaryKey().autoincrement(),
		userId: int('user_id').notNull().references(() => users.id),
		groupId: int('group_id').notNull().references(() => groups.id),
	}, (t) => [
		primaryKey({ columns: [t.userId, t.groupId] })
	]);

	export const usersToGroupsRelations = relations(usersToGroups, ({ one }) => ({
		group: one(groups, { fields: [usersToGroups.groupId], references: [groups.id] }),
		user: one(users, { fields: [usersToGroups.userId], references: [users.id] }),
	}));

	export const posts = singlestoreTable('posts', {
		id: int('id').primaryKey().autoincrement(),
		content: text('content').notNull(),
		authorId: int('author_id').references(() => users.id),
		createdAt: timestamp('created_at').notNull().defaultNow(),
	});

	export const postsRelations = relations(posts, ({ one, many }) => ({
		author: one(users, { fields: [posts.authorId], references: [users.id] }),
		comments: many(comments),
	}));

	export const comments = singlestoreTable('comments', {
		id: int('id').primaryKey().autoincrement(),
		content: text('content').notNull(),
		creator: int('creator').references(() => users.id),
		postId: int('post_id').references(() => posts.id),
		createdAt: timestamp('created_at').notNull().defaultNow(),
	});

	export const commentsRelations = relations(comments, ({ one, many }) => ({
		post: one(posts, { fields: [comments.postId], references: [posts.id] }),
		author: one(users, { fields: [comments.creator], references: [users.id] }),
		likes: many(commentLikes),
	}));

	export const commentLikes = singlestoreTable('comment_likes', {
		id: int('id').primaryKey().autoincrement(),
		creator: int('creator').references(() => users.id),
		commentId: int('comment_id').references(() => comments.id),
		createdAt: timestamp('created_at').notNull().defaultNow(),
	});

	export const commentLikesRelations = relations(commentLikes, ({ one }) => ({
		comment: one(comments, { fields: [commentLikes.commentId], references: [comments.id] }),
		author: one(users, { fields: [commentLikes.creator], references: [users.id] }),
	}));
```
</CodeTabs>

Drizzle provides `.findMany()` and `.findFirst()` APIs.
### Find many
<Section>
```typescript copy
const users = await db._query.users.findMany();
```
```ts
// result type
const result: {
	id: number;
	name: string;
	verified: boolean;
	invitedBy: number | null;
}[];
```
</Section>

### Find first
<Callout>
  `.findFirst()` will add `limit 1` to the query.
</Callout>
<Section>
```typescript copy
const user = await db._query.users.findFirst();
```
```ts
// result type
const result: {
	id: number;
	name: string;
	verified: boolean;
	invitedBy: number | null;
};
```
</Section>

### Include relations

`With` operator lets you combine data from multiple related tables and properly aggregate results.

**Getting all posts with comments:**
```typescript copy
const posts = await db._query.posts.findMany({
	with: {
		comments: true,
	},
});
```

**Getting first post with comments:**
```typescript copy
const post = await db._query.posts.findFirst({
	with: {
		comments: true,
	},
});
```

You can chain nested with statements as much as necessary.  
For any nested `with` queries Drizzle will infer types using [Core Type API](/docs/singlestore/goodies#type-api).
  
**Get all users with posts. Each post should contain a list of comments:**
```typescript copy
const users = await db._query.users.findMany({
	with: {
		posts: {
			with: {
				comments: true,
			},
		},
	},
});
```

### Partial fields select
`columns` parameter lets you include or omit columns you want to get from the database.

<Callout type="info" emoji="ℹ️">
  Drizzle performs partial selects on the query level, no additional data is transferred from the database.

  Keep in mind that **a single SQL statement is outputted by Drizzle.**
</Callout>

**Get all posts with just `id`, `content` and include `comments`:**
```typescript copy
const posts = await db._query.posts.findMany({
	columns: {
		id: true,
		content: true,
	},
	with: {
		comments: true,
	}
});
```

**Get all posts without `content`:**
```typescript copy
const posts = await db._query.posts.findMany({
	columns: {
		content: false,
	},
});
```

<Callout type="info" emoji="ℹ️">
When both `true` and `false` select options are present, all `false` options are ignored.
</Callout>

If you include the `name` field and exclude the `id` field, `id` exclusion will be redundant, 
all fields apart from `name` would be excluded anyways.  
  
**Exclude and Include fields in the same query:**
<Section>
```typescript copy
const users = await db._query.users.findMany({
	columns: {
		name: true,
		id: false //ignored
	},
});
```
```ts
// result type
const users: {
	name: string;
};
```
</Section>

**Only include columns from nested relations:**
<Section>
```typescript copy
const res = await db._query.users.findMany({
	columns: {},
	with: {
		posts: true
	}
});
```
```ts
// result type
const res: {
	posts: {
		id: number,
		text: string
	}
}[];
```
</Section>

### Nested partial fields select
Just like with **[`partial select`](#partial-select)**, you can include or exclude columns of nested relations:
```typescript copy
const posts = await db._query.posts.findMany({
	columns: {
		id: true,
		content: true,
	},
	with: {
		comments: {
			columns: {
				authorId: false
			}
		}
	}
});
```

### Select filters
Just like in our SQL-like query builder, 
relational queries API lets you define filters and conditions with the list of our **[`operators`](/docs/singlestore/operators)**.  

You can either import them from `drizzle-orm` or use from the callback syntax:
<Section>
```typescript copy
import { eq } from 'drizzle-orm';

const users = await db._query.users.findMany({
	where: eq(users.id, 1)
})
```
```ts copy
const users = await db._query.users.findMany({
	where: (users, { eq }) => eq(users.id, 1),
})
```
</Section>

Find post with `id=1` and comments that were created before particular date:
```typescript copy
await db._query.posts.findMany({
	where: (posts, { eq }) => (eq(posts.id, 1)),
	with: {
		comments: {
			where: (comments, { lt }) => lt(comments.createdAt, new Date()),
		},
	},
});
```

### Limit & Offset
Drizzle ORM provides `limit` & `offset` API for queries and for the nested entities.
  
**Find 5 posts:**
```typescript copy
await db._query.posts.findMany({
	limit: 5,
});
```

**Find posts and get 3 comments at most:**
```typescript copy
await db._query.posts.findMany({
	with: {
		comments: {
			limit: 3,
		},
	},
});
```

<Callout type="warning" emoji="⚠️">
  `offset` is only available for top level query.
</Callout>
```typescript 
await db._query.posts.findMany({
	limit: 5,
	offset: 2, // correct ✅
	with: {
		comments: {
			offset: 3, // incorrect ❌
			limit: 3,
		},
	},
});
```

Find posts with comments from the 5th to the 10th post:
```typescript copy
await db._query.posts.findMany({
	limit: 5,
  offset: 5,
	with: {
		comments: true,
	},
});
```

### Order By
Drizzle provides API for ordering in the relational query builder.  

You can use same ordering **[core API](/docs/singlestore/select#order-by)** or use
`order by` operator from the callback with no imports.  

<Section>
```typescript copy
import { desc, asc } from 'drizzle-orm';

await db._query.posts.findMany({
	orderBy: [asc(posts.id)],
});
```
```typescript copy
await db._query.posts.findMany({
	orderBy: (posts, { asc }) => [asc(posts.id)],
});
```
</Section>

**Order by `asc` + `desc`:**
```typescript copy
await db._query.posts.findMany({
	orderBy: (posts, { asc }) => [asc(posts.id)],
	with: {
		comments: {
			orderBy: (comments, { desc }) => [desc(comments.id)],
		},
	},
});
```

### Include custom fields
Relational query API lets you add custom additional fields. 
It's useful when you need to retrieve data and apply additional functions to it.
<Callout type="warning" emoji="⚠️">
	As of now aggregations are not supported in `extras`, please use **[`core queries`](/docs/singlestore/select)** for that.
</Callout>

<Section>
```typescript copy {5}
import { sql } from 'drizzle-orm';

await db._query.users.findMany({
	extras: {
		loweredName: sql`lower(${users.name})`.as('lowered_name'),
	},
})
```
```typescript copy {3}
await db._query.users.findMany({
	extras: {
		loweredName: (users, { sql }) => sql`lower(${users.name})`.as('lowered_name'),
	},
})
```
</Section>

`lowerName` as a key will be included to all fields in returned object.

<Callout type="warning" emoji="⚠️">
  You have to explicitly specify `.as("<name_for_column>")`
</Callout>

To retrieve all users with groups, but with the fullName field included (which is a concatenation of firstName and lastName), 
you can use the following query with the Drizzle relational query builder.

<Section>
```typescript copy
const res = await db._query.users.findMany({
	extras: {
		fullName: sql<string>`concat(${users.name}, " ", ${users.name})`.as('full_name'),
	},
	with: {
		usersToGroups: {
			with: {
				group: true,
			},
		},
	},
});
```
```ts
// result type
const res: {
	id: number;
	name: string;
	verified: boolean;
	invitedBy: number | null;
	fullName: string;
	usersToGroups: {
			group: {
					id: number;
					name: string;
					description: string | null;
			};
	}[];
}[];

```
</Section>

To retrieve all posts with comments and add an additional field to calculate the size of the post content and the size of each comment content:
<Section>
```typescript copy
const res = await db._query.posts.findMany({
	extras: (table, { sql }) => ({
		contentLength: (sql<number>`length(${table.content})`).as('content_length'),
	}),
	with: {
		comments: {
			extras: {
				commentSize: sql<number>`length(${comments.content})`.as('comment_size'),
			},
		},
	},
});
```
```ts
// result type
const res: {
	id: number;
	createdAt: Date;
	content: string;
	authorId: number | null;
	contentLength: number;
	comments: {
			id: number;
			createdAt: Date;
			content: string;
			creator: number | null;
			postId: number | null;
			commentSize: number;
	}[];
};
```
</Section>

### Prepared statements
Prepared statements are designed to massively improve query performance — [see here.](/docs/singlestore/perf-queries)

In this section, you can learn how to define placeholders and execute prepared statements 
using the Drizzle relational query builder.


Source: https://orm.drizzle.team/docs/singlestore/schemas

import Section from '@mdx/Section.astro';
import Callout from '@mdx/Callout.astro';

# Table schemas

If you declare an entity within a schema, query builder will prepend schema names in queries:<br/>
``select * from `schema`.`users```

<Section>
    ```ts {3,5}
    import { int, text, singlestoreSchema } from "drizzle-orm/singlestore-core";

    export const mySchema = singlestoreSchema("my_schema")

    export const mySchemaUsers = mySchema.table("users", {
      id: int("id").primaryKey().autoincrement(),
      name: text("name"),
    });
    ```
    ```sql
    CREATE SCHEMA `my_schema`;

    CREATE TABLE `my_schema`.`users` (
      `id` serial PRIMARY KEY,
      `name` text
    );
    ```
    </Section>

{/* TODO: ??? example > **Warning**
> If you will have tables with same names in different schemas then drizzle will respond with `never[]` error in result types and error from database
>
> In this case you may use [alias syntax](./joins#join-aliases-and-self-joins) */}


Source: https://orm.drizzle.team/docs/singlestore/seed-functions

import Callout from '@mdx/Callout.astro';
import Tab from "@mdx/Tab.astro";
import Tabs from "@mdx/Tabs.astro";

# Generators

<Callout title='warning'>
For now, specifying `arraySize` along with `isUnique` in generators that support it will result in unique values being generated (not unique arrays), which will then be packed into arrays.
</Callout>

## ---

### `default`

<rem025 />
Generates the same given value each time the generator is called.

|  | param          | default     | type
|:-| :--------      | :--------   | :--------
|  |`defaultValue`  |--           |`any`
|  |`arraySize`     |--           |`number`

<rem025 />

```ts 
import { seed } from "drizzle-seed";

await seed(db, schema, { count: 1000 }).refine((funcs) => ({
  posts: {
    columns: {
      content: funcs.default({
        // value you want to generate
        defaultValue: "post content",

        // number of elements in each one-dimensional array. 
        // (If specified, arrays will be generated.)
        arraySize: 3
      }),
    },
  },
}));

```

### `valuesFromArray`

<rem025 />
Generates values from given array

|  | param      | default                     | type
|:-| :--------  | :--------                   | :--------
|  |`values`    |--                           |`any[]` \| `{ weight: number; values: any[] }[]`
|  |`isUnique`  |`database column uniqueness` |`boolean`
|  |`arraySize` |--                           |`number`


<rem025 />
```ts 
import { seed } from "drizzle-seed";

await seed(db, schema, { count: 1000 }).refine((funcs) => ({
  posts: {
    columns: {
      title: funcs.valuesFromArray({
        // Array of values you want to generate (can be an array of weighted values)
        values: ["Title1", "Title2", "Title3", "Title4", "Title5"],

        // Property that controls whether the generated values will be unique or not
        isUnique: true,
        
        // number of elements in each one-dimensional array. 
        // (If specified, arrays will be generated.)
        arraySize: 3
      }),
    },
  },
}));

```

### `intPrimaryKey`

<rem025 />
Generates sequential integers starting from 1.

|  | param      | default    | type
|:-| :--------  | :--------  | :--------
|  |--          |--          |--

<rem025 />

```ts 
import { seed } from "drizzle-seed";

await seed(db, schema, { count: 1000 }).refine((funcs) => ({
  posts: {
    columns: {
      id: funcs.intPrimaryKey(),
    },
  },
}));

```

### `number`

<rem025 />
Generates numbers with a floating point within the given range

|  | param      | default                                                                                               | type
|:-| :--------  | :--------                                                                                             | :--------
|  |`isUnique`  |`database column uniqueness`                                                                           |`boolean`
|  |`precision` |`100`                                                                                                  |`number`
|  |`maxValue`  |``` `precision * 1000` if isUnique equals false``` ``` `precision * count` if isUnique equals true```  |`number`
|  |`minValue`  |`-maxValue`                                                                                            |`number`
|  |`arraySize` |--                                                                                                     |`number`

<rem025 />
```ts 
import { seed } from "drizzle-seed";

await seed(db, schema, { count: 1000 }).refine((funcs) => ({
  products: {
    columns: {
      unitPrice: funcs.number({
        // lower border of range.
        minValue: 10,

        // upper border of range.
        maxValue: 120,
        
        // precision of generated number:
        // precision equals 10 means that values will be accurate to one tenth (1.2, 34.6);
        // precision equals 100 means that values will be accurate to one hundredth (1.23, 34.67).
        precision: 100,

        // property that controls if generated values gonna be unique or not.
        isUnique: false,

        // number of elements in each one-dimensional array. 
        // (If specified, arrays will be generated.)
        arraySize: 3
      }),
    },
  },
}));

```

### `int`

<rem025 />
Generates integers within the given range

|  | param      | default                                                                            | type
|:-| :--------  | :--------                                                                          | :--------
|  |`isUnique`  |`database column uniqueness`                                                        |`boolean`
|  |`maxValue`  |``` `1000` if isUnique equals false``` ``` `count * 10` if isUnique equals true```  |`number \| bigint`
|  |`minValue`  |`-maxValue`                                                                         |`number \| bigint`
|  |`arraySize` |--                                                                                  |`number`

<rem025 />
```ts 
import { seed } from "drizzle-seed";

await seed(db, schema, { count: 1000 }).refine((funcs) => ({
  products: {
    columns: {
      unitsInStock: funcs.int({
        // lower border of range.
        minValue: 0,

        // lower border of range.
        maxValue: 100,

        // property that controls if generated values gonna be unique or not.
        isUnique: false,

        // number of elements in each one-dimensional array. 
        // (If specified, arrays will be generated.)
        arraySize: 3
      }),
    },
  },
}));

```

### `boolean`

<rem025 />
Generates boolean values (true or false)

|  | param      | default    | type
|:-| :--------  | :--------  | :--------
|  |`arraySize` |--          |`number`

<rem025 />
```ts 
import { seed } from "drizzle-seed";

await seed(db, schema, { count: 1000 }).refine((funcs) => ({
  users: {
    columns: {
      isAvailable: funcs.boolean({
        // number of elements in each one-dimensional array. 
        // (If specified, arrays will be generated.)
        arraySize: 3
      }),
    },
  },
}));

```

### `date`

<rem025 />
Generates a date within the given range

|  | param      | default                                                                                                   | type
|:-| :--------  | :--------------                                                                                           | :--------
|  |`minDate`   |``` `'2024-05-08' - 4 years` - if maxDate is not set``` ``` `maxDate - 8 years`  - if maxDate is set ```   |`string \| Date`
|  |`maxDate`   |``` `'2024-05-08' + 4 years` - if minDate is not set``` ``` `minDate + 8 years`  - if minDate is set ```   |`string \| Date`
|  |`arraySize` |--                                                                                                         |`number`

<Callout type='warning'>
If only one of the parameters (`minDate` or `maxDate`) is provided, the unspecified parameter will be calculated by adding or subtracting 8 years to/from the specified one
</Callout>

<rem025 />
```ts 
import { seed } from "drizzle-seed";

await seed(db, schema, { count: 1000 }).refine((funcs) => ({
  users: {
    columns: {
      birthDate: funcs.date({
        // lower border of range.
        minDate: "1990-01-01",

        // upper border of range.
        maxDate: "2010-12-31",

        // number of elements in each one-dimensional array. 
        // (If specified, arrays will be generated.)
        arraySize: 3
      }),
    },
  },
}));

```

### `time`

<rem025 />
Generates time in 24-hour format

|  | param      | default             | type
|:-| :--------  | :--------           | :--------
|  |`min`       |`'00:00:00.000Z'`    |`string \| Date`
|  |`max`       |`'23:59:59.999Z'`    |`string \| Date`
|  |`arraySize` |--                   |`number`

<rem025 />
```ts 
import { seed } from "drizzle-seed";

await seed(db, schema, { count: 1000 }).refine((funcs) => ({
  users: {
    columns: {
      birthTime: funcs.time({
        // lower border of range.
        min: "11:12:13.141",

        // upper border of range.
        max: "15:16:17.181",

        // number of elements in each one-dimensional array. 
        // (If specified, arrays will be generated.)
        arraySize: 3
      }),
    },
  },
}));

```

### `timestamp`

<rem025 />
Generates timestamps

|  | param           | default                                                                                       | type
|:-| :--------       | :--------                                                                                     | :--------
|  |`min`            |``` `'2024-05-08' - 2 years` - if max is not set``` ``` `max - 4 years`  - if max is set ```   |`string \| Date`
|  |`max`            |``` `'2024-05-08' + 2 years` - if min is not set``` ``` `min + 4 years`  - if min is set ```   |`string \| Date`
|  |`arraySize`      |--                                                                                             |`number`

<rem025 />
```ts 
import { seed } from "drizzle-seed";

await seed(db, schema, { count: 1000 }).refine((funcs) => ({
  orders: {
    columns: {
      shippedDate: funcs.timestamp({
        // lower border of range.
        min: "2025-03-07T11:12:13.141",

        // upper border of range.
        max: "2025-03-08T15:16:17.181",

        // number of elements in each one-dimensional array. 
        // (If specified, arrays will be generated.)
        arraySize: 3
      }),
    },
  },
}));

```

### `datetime`

<rem025 />
Generates datetime objects

|  | param        | default                                                                                       | type
|:-| :--------    | :--------                                                                                     | :--------
|  |`min`         |``` `'2024-05-08' - 2 years` - if max is not set``` ``` `max - 4 years`  - if max is set ```   |`string \| Date`
|  |`max`         |``` `'2024-05-08' + 2 years` - if min is not set``` ``` `min + 4 years`  - if min is set ```   |`string \| Date`
|  |`arraySize`   |--                                                                                             |`number`
<rem025 />
```ts 
import { seed } from "drizzle-seed";

await seed(db, schema, { count: 1000 }).refine((funcs) => ({
  orders: {
    columns: {
      shippedDate: funcs.datetime({
        // lower border of range.
        min: "2025-03-07 13:12:13Z",
        
        // upper border of range.
        max: "2025-03-09 15:12:13Z",

        // number of elements in each one-dimensional array. 
        // (If specified, arrays will be generated.)
        arraySize: 3
      }),
    },
  },
}));

```

### `year`

<rem025 />
Generates years in `YYYY` format

|  | param      | default    | type
|:-| :--------  | :--------  | :--------
|  |`arraySize` |--          |`number`

<rem025 />
```ts 
import { seed } from "drizzle-seed";

await seed(db, schema, { count: 1000 }).refine((funcs) => ({
  users: {
    columns: {
      birthYear: funcs.year({
        // number of elements in each one-dimensional array. 
        // (If specified, arrays will be generated.)
        arraySize: 3
      }),
    },
  },
}));

```

### `json`

<rem025 />
Generates JSON objects with a fixed structure

```ts
{ email, name, isGraduated, hasJob, salary, startedWorking, visitedCountries}

// or

{ email, name, isGraduated, hasJob, visitedCountries }
```

> The JSON structure will be picked randomly

|  | param      | default    | type
|:-| :--------  | :--------  | :--------
|  |`arraySize` |--          |`number`

<rem025 />
```ts 
import { seed } from "drizzle-seed";

await seed(db, schema, { count: 1000 }).refine((funcs) => ({
  users: {
    columns: {
      metadata: funcs.json({
        // number of elements in each one-dimensional array. 
        // (If specified, arrays will be generated.)
        arraySize: 3
      }),
    },
  },
}));

```

### `interval`

<rem025 />
Generates time intervals.

Example of a generated value: `1 year 12 days 5 minutes`

|  | param      | default                     | type
|:-| :--------  | :--------                   | :--------
|  |`isUnique`  |`database column uniqueness` |`boolean`
|  |`arraySize` |--                           |`number`

<rem025 />
```ts 
import { seed } from "drizzle-seed";

await seed(db, schema, { count: 1000 }).refine((funcs) => ({
  users: {
    columns: {
      timeSpentOnWebsite: funcs.interval({
        // `isUnique` - property that controls whether the generated values will be unique or not
        isUnique: true,

        // number of elements in each one-dimensional array. 
        // (If specified, arrays will be generated.)
        arraySize: 3
      }),
    },
  },
}));

```

### `string`

<rem025 />
Generates random strings

|  | param      | default                     | type
|:-| :--------  | :--------                   | :--------
|  |`isUnique`  |`database column uniqueness` |`boolean`
|  |`arraySize` |--                           |`number`

<rem025 />
```ts 
import { seed } from "drizzle-seed";

await seed(db, schema, { count: 1000 }).refine((funcs) => ({
  users: {
    columns: {
      hashedPassword: funcs.string({
        // `isUnique` - property that controls whether the generated values will be unique or not
        isUnique: false,
        
        // number of elements in each one-dimensional array. 
        // (If specified, arrays will be generated.)
        arraySize: 3
      }),
    },
  },
}));

```

### `uuid`

<rem025 />
Generates v4 UUID strings

|  | param      | default    | type
|:-| :--------  | :--------  | :--------
|  |`arraySize` |--          |`number`

<rem025 />
```ts 
import { seed } from "drizzle-seed";
await seed(db, schema, { count: 1000 }).refine((funcs) => ({
  products: {
    columns: {
      id: funcs.uuid({
        // number of elements in each one-dimensional array. 
        // (If specified, arrays will be generated.)
        arraySize: 3
      }),
    },
  },
}));
```

### `firstName`

<rem025 />
Generates a person's first name

|  | param      | default                     | type
|:-| :--------  | :--------                   | :--------
|  |`isUnique`  |`database column uniqueness` |`boolean`
|  |`arraySize` |--                           |`number`

<rem025 />
```ts 
import { seed } from "drizzle-seed";

await seed(db, schema, { count: 1000 }).refine((funcs) => ({
  users: {
    columns: {
      firstName: funcs.firstName({
        // `isUnique` - property that controls whether the generated values will be unique or not
        isUnique: true,

        // number of elements in each one-dimensional array. 
        // (If specified, arrays will be generated.)
        arraySize: 3
      }),
    },
  },
}));

```

### `lastName`

<rem025 />
Generates a person's last name

|  | param      | default                     | type
|:-| :--------  | :--------                   | :--------
|  |`isUnique`  |`database column uniqueness` |`boolean`
|  |`arraySize` |--                           |`number`

<rem025 />
```ts 
import { seed } from "drizzle-seed";

await seed(db, schema, { count: 1000 }).refine((funcs) => ({
  users: {
    columns: {
      lastName: funcs.lastName({
        // `isUnique` - property that controls whether the generated values will be unique or not
        isUnique: false,
        
        // number of elements in each one-dimensional array. 
        // (If specified, arrays will be generated.)
        arraySize: 3
      }),
    },
  },
}));

```

### `fullName`

<rem025 />
Generates a person's full name

|  | param      | default                     | type
|:-| :--------  | :--------                   | :--------
|  |`isUnique`  |`database column uniqueness` |`boolean`
|  |`arraySize` |--                           |`number`

<rem025 />
```ts 
import { seed } from "drizzle-seed";

await seed(db, schema, { count: 1000 }).refine((funcs) => ({
  users: {
    columns: {
      fullName: funcs.fullName({
        // `isUnique` - property that controls whether the generated values will be unique or not
        isUnique: true,

        // number of elements in each one-dimensional array. 
        // (If specified, arrays will be generated.)
        arraySize: 3
      }),
    },
  },
}));

```

### `email`

<rem025 />
Generates unique email addresses

|  | param      | default    | type
|:-| :--------  | :--------  | :--------
|  |`arraySize` |--          |`number`

<rem025 />
```ts 
import { seed } from "drizzle-seed";

await seed(db, schema, { count: 1000 }).refine((funcs) => ({
  users: {
    columns: {
      email: funcs.email({
        // number of elements in each one-dimensional array. 
        // (If specified, arrays will be generated.)
        arraySize: 3
      }),
    },
  },
}));

```

### `phoneNumber`

<rem025 />
Generates unique phone numbers

|  | param                    | default                                         | type
|:-| :--------                | :--------                                       | :--------
|  |`template`                |--                                               |`string`
|  |`prefixes`                |[Used dataset for prefixes](https://github.com/OleksiiKH0240/drizzle-orm/blob/main/drizzle-seed/src/datasets/phonesInfo.ts)   |`string[]`
|  |`generatedDigitsNumbers`  | `7` - `if prefixes was defined`                 |`number \| number[]`
|  |`arraySize`               |--                                               |`number`

<rem025 />
```ts 
import { seed } from "drizzle-seed";

//generate phone number using template property
await seed(db, schema, { count: 1000 }).refine((funcs) => ({
  users: {
    columns: {
      phoneNumber: funcs.phoneNumber({ 
        // `template` - phone number template, where all '#' symbols will be substituted with generated digits.
        template: "+(380) ###-####",

        // number of elements in each one-dimensional array. 
        // (If specified, arrays will be generated.)
        arraySize: 3
      }),
    },
  },
}));

```
```ts 
import { seed } from "drizzle-seed";

//generate phone number using prefixes and generatedDigitsNumbers properties
await seed(db, schema, { count: 1000 }).refine((funcs) => ({
  users: {
    columns: {
      phoneNumber: funcs.phoneNumber({
        // `prefixes` - array of any string you want to be your phone number prefixes.(not compatible with `template` property)
        prefixes: ["+380 99", "+380 67"],

        // `generatedDigitsNumbers` - number of digits that will be added at the end of prefixes.(not compatible with `template` property)
        generatedDigitsNumbers: 7,

        // number of elements in each one-dimensional array. 
        // (If specified, arrays will be generated.)
        arraySize: 3
      }),
    },
  },
}));

```
```ts 
import { seed } from "drizzle-seed";

// generate phone number using prefixes and generatedDigitsNumbers properties but with different generatedDigitsNumbers for prefixes
await seed(db, schema, { count: 1000 }).refine((funcs) => ({
  users: {
    columns: {
      phoneNumber: funcs.phoneNumber({
        // `prefixes` - array of any string you want to be your phone number prefixes.(not compatible with `template` property)
        prefixes: ["+380 99", "+380 67", "+1"],

        // `generatedDigitsNumbers` - number of digits that will be added at the end of prefixes.(not compatible with `template` property)
        generatedDigitsNumbers: [7, 7, 10],

        // number of elements in each one-dimensional array. 
        // (If specified, arrays will be generated.)
        arraySize: 3
      }),
    },
  },
}));

```
### `country`

<rem025 />
Generates country's names

|  | param      | default                     | type
|:-| :--------  | :--------                   | :--------
|  |`isUnique`  |`database column uniqueness` |`boolean`
|  |`arraySize` |--                           |`number`

<rem025 />

```ts 
import { seed } from "drizzle-seed";

await seed(db, schema, { count: 1000 }).refine((funcs) => ({
  users: {
    columns: {
      country: funcs.country({
        // `isUnique` - property that controls whether the generated values will be unique or not
        isUnique: false,
        
        // number of elements in each one-dimensional array. 
        // (If specified, arrays will be generated.)
        arraySize: 3
      }),
    },
  },
}));

```

### `city`

<rem025 />
Generates city's names

|  | param      | default                     | type
|:-| :--------  | :--------                   | :--------
|  |`isUnique`  |`database column uniqueness` |`boolean`
|  |`arraySize` |--                           |`number`

<rem025 />

```ts 
import { seed } from "drizzle-seed";

await seed(db, schema, { count: 1000 }).refine((funcs) => ({
  users: {
    columns: {
      city: funcs.city({
        // `isUnique` - property that controls whether the generated values will be unique or not
        isUnique: false,

        // number of elements in each one-dimensional array. 
        // (If specified, arrays will be generated.)
        arraySize: 3
      }),
    },
  },
}));

```

### `streetAddress`

<rem025 />
Generates street address

|  | param      | default                     | type
|:-| :--------  | :--------                   | :--------
|  |`isUnique`  |`database column uniqueness` |`boolean`
|  |`arraySize` |--                           |`number`

<rem025 />

```ts 
import { seed } from "drizzle-seed";

await seed(db, schema, { count: 1000 }).refine((funcs) => ({
  users: {
    columns: {
      streetAddress: funcs.streetAddress({
        // `isUnique` - property that controls whether the generated values will be unique or not
        isUnique: false,
        
        // number of elements in each one-dimensional array. 
        // (If specified, arrays will be generated.)
        arraySize: 3 
      }),
    },
  },
}));

```

### `jobTitle`

<rem025 />
Generates job titles

|  | param      | default    | type
|:-| :--------  | :--------  | :--------
|  |`arraySize` |--          |`number`

<rem025 />

```ts 
import { seed } from "drizzle-seed";

await seed(db, schema, { count: 1000 }).refine((funcs) => ({
  users: {
    columns: {
      jobTitle: funcs.jobTitle({
        // number of elements in each one-dimensional array. 
        // (If specified, arrays will be generated.)
        arraySize: 3
      }),
    },
  },
}));

```

### `postcode`

<rem025 />
Generates postal codes

|  | param      | default                     | type
|:-| :--------  | :--------                   | :--------
|  |`isUnique`  |`database column uniqueness` |`boolean`
|  |`arraySize` |--                           |`number`

<rem025 />

```ts 
import { seed } from "drizzle-seed";

await seed(db, schema, { count: 1000 }).refine((funcs) => ({
  users: {
    columns: {
      postcode: funcs.postcode({
        // `isUnique` - property that controls whether the generated values will be unique or not
        isUnique: true,

        // number of elements in each one-dimensional array. 
        // (If specified, arrays will be generated.)
        arraySize: 3
      }),
    },
  },
}));

```

### `state`

<rem025 />
Generates US states

|  | param      | default    | type
|:-| :--------  | :--------  | :--------
|  |`arraySize` |--          |`number`

<rem025 />

```ts 
import { seed } from "drizzle-seed";

await seed(db, schema, { count: 1000 }).refine((funcs) => ({
  users: {
    columns: {
      state: funcs.state({
        // number of elements in each one-dimensional array. 
        // (If specified, arrays will be generated.)
        arraySize: 3
      }),
    },
  },
}));

```

### `companyName`

<rem025 />
Generates random company's names

|  | param      | default                     | type
|:-| :--------  | :--------                   | :--------
|  |`isUnique`  |`database column uniqueness` |`boolean`
|  |`arraySize` |--                           |`number`

<rem025 />

```ts 
import { seed } from "drizzle-seed";

await seed(db, schema, { count: 1000 }).refine((funcs) => ({
  users: {
    columns: {
      company: funcs.companyName({ 
        // `isUnique` - property that controls whether the generated values will be unique or not
        isUnique: true,

        // number of elements in each one-dimensional array. 
        // (If specified, arrays will be generated.)
        arraySize: 3
      }),
    },
  },
}));

```
### `loremIpsum`

<rem025 />
Generates `lorem ipsum` text sentences.

|  | param            | default    | type
|:-| :--------        | :--------  | :--------
|  |`sentencesCount`  | 1          |`number`
|  |`arraySize`       |--          |`number`

<rem025 />

```ts 
import { seed } from "drizzle-seed";

await seed(db, schema, { count: 1000 }).refine((funcs) => ({
  posts: {
    columns: {
      content: funcs.loremIpsum({
        // `sentencesCount` - number of sentences you want to generate as one generated value(string).
        sentencesCount: 2,

        // number of elements in each one-dimensional array. 
        // (If specified, arrays will be generated.)
        arraySize: 3
      }),
    },
  },
}));

```

### `point`

<rem025 />
Generates 2D points within specified ranges for x and y coordinates.

|  | param       | default                                                                                 | type
|:-| :--------   | :--------                                                                               | :--------
|  |`isUnique`   |`database column uniqueness`                                                             |`boolean`
|  |`maxXValue`  |``` `10 * 1000` if isUnique equals false``` ``` `10 * count` if isUnique equals true```  |`number`
|  |`minXValue`  |`-maxXValue`                                                                             |`number`
|  |`maxYValue`  |``` `10 * 1000` if isUnique equals false``` ``` `10 * count` if isUnique equals true```  |`number`
|  |`minYValue`  |`-maxYValue`                                                                             |`number`
|  |`arraySize`  |--                                                                                       |`number`


<rem025 />

```ts 
import { seed } from "drizzle-seed";

await seed(db, schema, { count: 1000 }).refine((funcs) => ({
  triangles: {
    columns: {
      pointCoords: funcs.point({
        // `isUnique` - property that controls if generated values gonna be unique or not.
        isUnique: true,

        // `minXValue` - lower bound of range for x coordinate.
        minXValue: -5,

        // `maxXValue` - upper bound of range for x coordinate.
        maxXValue: 20,

        // `minYValue` - lower bound of range for y coordinate.
        minYValue: 0,

        // `maxYValue` - upper bound of range for y coordinate.
        maxYValue: 30,

        // number of elements in each one-dimensional array. 
        // (If specified, arrays will be generated.)
        arraySize: 3
      }),
    },
  },
}));

```

### `line`

<rem025 />
Generates 2D lines within specified ranges for a, b and c parameters of line.

```
line equation: a*x + b*y + c = 0
```

|  | param       | default                                                                                 | type
|:-| :--------   | :--------                                                                               | :--------
|  |`isUnique`   |`database column uniqueness`                                                             |`boolean`
|  |`maxAValue`  |``` `10 * 1000` if isUnique equals false``` ``` `10 * count` if isUnique equals true```  |`number`
|  |`minAValue`  |`-maxAValue`                                                                             |`number`
|  |`maxBValue`  |``` `10 * 1000` if isUnique equals false``` ``` `10 * count` if isUnique equals true```  |`number`
|  |`minBValue`  |`-maxBValue`                                                                             |`number`
|  |`maxCValue`  |``` `10 * 1000` if isUnique equals false``` ``` `10 * count` if isUnique equals true```  |`number`
|  |`minCValue`  |`-maxCValue`                                                                             |`number`
|  |`arraySize`  |--                                                                                       |`number`
<rem025 />

```ts 
import { seed } from "drizzle-seed";

await seed(db, schema, { count: 1000 }).refine((funcs) => ({
  lines: {
    columns: {
      lineParams: funcs.point({
        // `isUnique` - property that controls if generated values gonna be unique or not.
        isUnique: true,

        // `minAValue` - lower bound of range for a parameter.
        minAValue: -5,

        // `maxAValue` - upper bound of range for x parameter.
        maxAValue: 20,

        // `minBValue` - lower bound of range for y parameter.
        minBValue: 0,

        // `maxBValue` - upper bound of range for y parameter.
        maxBValue: 30,

        // `minCValue` - lower bound of range for y parameter.
        minCValue: 0,

        // `maxCValue` - upper bound of range for y parameter.
        maxCValue: 10,

        // number of elements in each one-dimensional array. 
        // (If specified, arrays will be generated.)
        arraySize: 3
      }),
    },
  },
}));

```

### `bitString`

<rem025 />
Generates bit strings based on specified parameters.

|  | param       | default                                                                                 | type
|:-| :--------   | :--------                                                                               | :--------
|  |`isUnique`   |`database column uniqueness`                                                             |`boolean`
|  |`dimensions` |`database column bit-length`                                                             |`number`
|  |`arraySize`  |--                                                                                       |`number`
<rem025 />

```ts 
import { seed } from "drizzle-seed";

await seed(db, schema, { count: 1000 }).refine((funcs) => ({
  bitStringTable: {
    columns: {
      bit: funcs.bitString({
        // desired length of each bit string (e.g., `dimensions = 3` produces values like `'010'`).
        dimensions: 12,

        // property that controls if generated values gonna be unique or not;
        isUnique: true,

        // number of elements in each one-dimensional array (If specified, arrays will be generated);
        arraySize: 3,
      }),
    },
  },
}));

```

### `inet`

<rem025 />
Generates ip addresses based on specified parameters.

|  | param       | default                                                                                 | type
|:-| :--------   | :--------                                                                               | :--------
|  |`isUnique`   |`database column uniqueness`                                                             |`boolean`
|  |`arraySize`  |--                                                                                       |`number`
|  |`ipAddress`  |`'ipv4'`                                                                                 |`'ipv4' \| 'ipv6'`
|  |`includeCidr`|`true`                                                                                   |`boolean`
<rem025 />

```ts 
import { seed } from "drizzle-seed";

await seed(db, schema, { count: 1000 }).refine((funcs) => ({
  inetTable: {
    columns: {
      inet: funcs.inet({
        // property that controls if generated values gonna be unique or not;
        isUnique: true,

        // number of elements in each one-dimensional array (If specified, arrays will be generated);
        arraySize: 3,

        // type of IP address to generate — either "ipv4" or "ipv6";
        ipAddress: "ipv4",

        // determines whether generated IPs include a CIDR suffix.
        includeCidr: true,
      }),
    },
  },
}));
```


### `vector`

<rem025 />
Generates vectors based on the provided parameters.

|  | param          | default                                                      | type
|:-| :--------      | :--------                                                    | :--------
|  |`isUnique`      |`database column uniqueness`                                  |`boolean`
|  |`arraySize`     |--                                                            |`number`
|  |`decimalPlaces` |`2`                                                           |`number`
|  |`dimensions`    |`database column’s dimensions`                                |`number`
|  |`minValue`      |`-1000`                                                       |`number`
|  |`maxValue`      |`1000`                                                        |`number`
<rem025 />

```ts 
import { seed } from "drizzle-seed";

await seed(db, schema, { count: 1000 }).refine((funcs) => ({
  vectorTable: {
    columns: {
      vector: funcs.vector({
        // property that controls if generated values gonna be unique or not;
        isUnique: true,

        // number of elements in each one-dimensional array (If specified, arrays will be generated);
        arraySize: 3,

        // number of decimal places for each vector element (e.g., `decimalPlaces = 3` produces values like `1.123`);
        decimalPlaces: 5,

        // number of elements in each generated vector (e.g., `dimensions = 3` produces values like `[1,2,3]`);
        dimensions: 12,

        // minimum allowed value for each vector element;
        minValue: -100,

        // maximum allowed value for each vector element.
        maxValue: 100,
      }),
    },
  },
}));

```

Source: https://orm.drizzle.team/docs/singlestore/seed-overview

import Npm from "@mdx/Npm.astro";
import Tab from "@mdx/Tab.astro";
import Tabs from "@mdx/Tabs.astro";
import Callout from '@mdx/Callout.astro';
import CodeTabs from "@mdx/CodeTabs.astro";
import Section from "@mdx/Section.astro";

# Drizzle Seed

`drizzle-seed` is a TypeScript library that helps you generate deterministic, yet realistic,
fake data to populate your database. By leveraging a seedable pseudorandom number generator (pRNG),
it ensures that the data you generate is consistent and reproducible across different runs.
This is especially useful for testing, development, and debugging purposes.

#### What is Deterministic Data Generation?

Deterministic data generation means that the same input will always produce the same output.
In the context of `drizzle-seed`, when you initialize the library with the same seed number,
it will generate the same sequence of fake data every time. This allows for predictable and repeatable data sets.

#### Pseudorandom Number Generator (pRNG)

A pseudorandom number generator is an algorithm that produces a sequence of numbers
that approximates the properties of random numbers. However, because it's based on an initial value
called a seed, you can control its randomness. By using the same seed, the pRNG will produce the
same sequence of numbers, making your data generation process reproducible.

#### Benefits of Using a pRNG:

- Consistency: Ensures that your tests run on the same data every time.
- Debugging: Makes it easier to reproduce and fix bugs by providing a consistent data set.
- Collaboration: Team members can share seed numbers to work with the same data sets.

With drizzle-seed, you get the best of both worlds: the ability to generate realistic fake data and the control to reproduce it whenever needed.

## Installation

<Npm>drizzle-seed</Npm>

## Basic Usage

In this example we will create 10 users with random names and ids

```ts {12}
import { singlestoreTable, int, varchar } from "drizzle-orm/singlestore-core";
import { drizzle } from "drizzle-orm/singlestore";
import { seed } from "drizzle-seed";

const users = singlestoreTable("users", {
  id: int().primaryKey().autoincrement(),
  name: varchar({ length: 255 }).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

```ts
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

```ts
await seed(db, schema, { seed: 12345 });
```

## Reset database

With `drizzle-seed`, you can easily reset your database and seed it with new values, for example, in your test suites

```ts
// path to a file with schema you want to reset
import * as schema from "./schema.ts";
import { reset } from "drizzle-seed";

async function main() {
  const db = drizzle(process.env.DATABASE_URL!);
  await reset(db, schema);
}

main();
```

Different dialects will have different strategies for database resetting. For SingleStore:

For SingleStore, the `drizzle-seed` package will first disable `FOREIGN_KEY_CHECKS` to ensure the next step won't fail, and then generate `TRUNCATE` statements to empty the content of all tables

```sql
SET FOREIGN_KEY_CHECKS = 0;
TRUNCATE tableName1;
TRUNCATE tableName2;
...
SET FOREIGN_KEY_CHECKS = 1;
```

## Refinements

In case you need to change the behavior of the seed generator functions that `drizzle-seed` uses by default, you can specify your own implementation and even use your own list of values for the seeding process

`.refine` is a callback that receives a list of all available generator functions from `drizzle-seed`. It should return an object with keys representing the tables you want to refine, defining their behavior as needed. 
Each table can specify several properties to simplify seeding your database:

<rem025 />

- `columns`: Refine the default behavior of each column by specifying the required generator function, or exclude the column from seeding by specifying `false`.
- `count`: Specify the number of rows to insert into the database. By default, it's 10. If a global count is defined in the `seed()` options, the count defined here will override it for this specific table.
- `with`: Define how many referenced entities to create for each parent table if you want to generate associated entities.

<Callout title='info'>
You can also specify a weighted random distribution for the number of referenced values you want to create. For details on this API, you can refer to [Weighted Random docs](#weighted-random) docs section
</Callout>

**API**
```ts
await seed(db, schema).refine((f) => ({
  users: {
    columns: {},
    count: 10,
    with: {
        posts: 10
    }
  },
}));
```

Let's check a few examples with an explanation of what will happen:

```ts filename='schema.ts'
import { singlestoreTable, int, varchar } from "drizzle-orm/singlestore-core";

export const users = singlestoreTable("users", {
  id: int().primaryKey().autoincrement(),
  name: varchar({ length: 255 }).notNull(),
});

export const posts = singlestoreTable("posts", {
  id: int().primaryKey().autoincrement(),
  description: varchar({ length: 255 }),
  userId: int().references(() => users.id),
});
```

**Example 1**: Seed only the `users` table with 20 entities and with refined seed logic for the `name` column
```ts filename='index.ts'
import { drizzle } from "drizzle-orm/singlestore";
import { seed } from "drizzle-seed";
import * as schema from './schema.ts'

async function main() {
  const db = drizzle(process.env.DATABASE_URL!);

  await seed(db, { users: schema.users }).refine((f) => ({
    users: {
        columns: {
            name: f.fullName(),
        },
        count: 20
    }
  }));
}

main();
```

**Example 2**: Seed only the `users` table, excluding the `name` column from seeding
```ts filename='index.ts'
import { drizzle } from "drizzle-orm/singlestore";
import { seed } from "drizzle-seed";
import * as schema from './schema.ts'

async function main() {
  const db = drizzle(process.env.DATABASE_URL!);

  await seed(db, { users: schema.users }).refine((f) => ({
    users: {
        columns: {
            name: false, // the name column will not be seeded, allowing the database to use its default value.
        }
    }
  }));
}

main();
```

**Example 3**: Seed the `users` table with 20 entities and add 10 `posts` for each `user` by seeding the `posts` table and creating a reference from `posts` to `users`
```ts filename='index.ts'
import { drizzle } from "drizzle-orm/singlestore";
import { seed } from "drizzle-seed";
import * as schema from './schema.ts'

async function main() {
  const db = drizzle(process.env.DATABASE_URL!);

  await seed(db, schema).refine((f) => ({
    users: {
        count: 20,
        with: {
            posts: 10
        }
    }
  }));
}

main();
```

**Example 4**: Seed the `users` table with 5 entities and populate the database with 100 `posts` without connecting them to the `users` entities. Refine `id` generation for `users` so 
that it will give any int from `10000` to `20000` and remains unique, and refine `posts` to retrieve values from a self-defined array
```ts filename='index.ts'
import { drizzle } from "drizzle-orm/singlestore";
import { seed } from "drizzle-seed";
import * as schema from './schema.ts'

async function main() {
  const db = drizzle(process.env.DATABASE_URL!);

  await seed(db, schema).refine((f) => ({
    users: {
        count: 5,
        columns: {
            id: f.int({
              minValue: 10000,
              maxValue: 20000,
              isUnique: true,
            }),
        }
    },
    posts: {
        count: 100,
        columns: {
            description: f.valuesFromArray({
            values: [
                "The sun set behind the mountains, painting the sky in hues of orange and purple", 
                "I can't believe how good this homemade pizza turned out!", 
                "Sometimes, all you need is a good book and a quiet corner.", 
                "Who else thinks rainy days are perfect for binge-watching old movies?", 
                "Tried a new hiking trail today and found the most amazing waterfall!",
                // ...
            ],
          })
        }
    }
  }));
}

main();
```

<Callout type='warning'>
There are many more possibilities that we will define in these docs, but for now, you can explore a few sections in this documentation. Check the [Generators](/docs/singlestore/seed-functions) section to get familiar with all the available generator functions you can use.

A particularly great feature is the ability to use weighted randomization, both for generator values created for a column and for determining the number of related entities that can be generated by `drizzle-seed`.

Please check [Weighted Random docs](#weighted-random) for more info.
</Callout>


## Weighted Random

There may be cases where you need to use multiple datasets with a different priority that should be inserted into your database during the seed stage. For such cases, drizzle-seed provides an API called weighted random

The Drizzle Seed package has a few places where weighted random can be used:

- Columns inside each table refinements
- The `with` property, determining the amount of related entities to be created

Let's check an example for both:

```ts filename="schema.ts"
import { singlestoreTable, int, varchar, double } from "drizzle-orm/singlestore-core";

export const orders = singlestoreTable(
  "orders",
  {
    id: int().primaryKey().autoincrement(),
    name: varchar({ length: 255 }).notNull(),
    quantityPerUnit: varchar().notNull(),
    unitPrice: double().notNull(),
    unitsInStock: int().notNull(),
    unitsOnOrder: int().notNull(),
    reorderLevel: int().notNull(),
    discontinued: int().notNull(),
  }
);

export const details = singlestoreTable(
  "details",
  {
    unitPrice: double().notNull(),
    quantity: int().notNull(),
    discount: double().notNull(),

    orderId: int()
      .notNull()
      .references(() => orders.id, { onDelete: "cascade" }),
  }
);
```

**Example 1**: Refine the `unitPrice` generation logic to generate `5000` random prices, with a 30% chance of prices between 10-100 and a 70% chance of prices between 100-300

```ts filename="index.ts"
import { drizzle } from "drizzle-orm/singlestore";
import { seed } from "drizzle-seed";
import * as schema from './schema.ts'

async function main() {
  const db = drizzle(process.env.DATABASE_URL!);

  await seed(db, schema).refine((f) => ({
    orders: {
       count: 5000,
       columns: {
           unitPrice: f.weightedRandom(
               [
                   {
                       weight: 0.3,
                       value: funcs.int({ minValue: 10, maxValue: 100 })
                   },
                   {
                       weight: 0.7,
                       value: funcs.number({ minValue: 100, maxValue: 300, precision: 100 })
                   }
               ]
           ),
       }
    }
  }));
}

main();
```

**Example 2**: For each order, generate 1 to 3 details with a 60% chance, 5 to 7 details with a 30% chance, and 8 to 10 details with a 10% chance

```ts filename="index.ts"
import { drizzle } from "drizzle-orm/singlestore";
import { seed } from "drizzle-seed";
import * as schema from './schema.ts'

async function main() {
  const db = drizzle(process.env.DATABASE_URL!);

  await seed(db, schema).refine((f) => ({
    orders: {
       with: {
           details:
               [
                   { weight: 0.6, count: [1, 2, 3] },
                   { weight: 0.3, count: [5, 6, 7] },
                   { weight: 0.1, count: [8, 9, 10] },
               ]
       }
    }
  }));
}

main();
```

## Complex example

<CodeTabs items={["main.ts", "schema.ts"]}>
<Section>
```ts
import { seed } from "drizzle-seed";
import * as schema from "./schema.ts";

const main = async () => {
    const titlesOfCourtesy = ["Ms.", "Mrs.", "Dr."];
    const unitsOnOrders = [0, 10, 20, 30, 50, 60, 70, 80, 100];
    const reorderLevels = [0, 5, 10, 15, 20, 25, 30];
    const quantityPerUnit = [
        "100 - 100 g pieces",
        "100 - 250 g bags",
        "10 - 200 g glasses",
        "10 - 4 oz boxes",
        "10 - 500 g pkgs.",
        "10 - 500 g pkgs."
    ];
    const discounts = [0.05, 0.15, 0.2, 0.25];

    await seed(db, schema).refine((funcs) => ({
        customers: {
            count: 10000,
            columns: {
                companyName: funcs.companyName(),
                contactName: funcs.fullName(),
                contactTitle: funcs.jobTitle(),
                address: funcs.streetAddress(),
                city: funcs.city(),
                postalCode: funcs.postcode(),
                region: funcs.state(),
                country: funcs.country(),
                phone: funcs.phoneNumber({ template: "(###) ###-####" }),
                fax: funcs.phoneNumber({ template: "(###) ###-####" })
            }
        },
        employees: {
            count: 200,
            columns: {
                firstName: funcs.firstName(),
                lastName: funcs.lastName(),
                title: funcs.jobTitle(),
                titleOfCourtesy: funcs.valuesFromArray({ values: titlesOfCourtesy }),
                birthDate: funcs.date({ minDate: "2010-12-31", maxDate: "2010-12-31" }),
                hireDate: funcs.date({ minDate: "2010-12-31", maxDate: "2024-08-26" }),
                address: funcs.streetAddress(),
                city: funcs.city(),
                postalCode: funcs.postcode(),
                country: funcs.country(),
                homePhone: funcs.phoneNumber({ template: "(###) ###-####" }),
                extension: funcs.int({ minValue: 428, maxValue: 5467 }),
                notes: funcs.loremIpsum()
            }
        },
        orders: {
            count: 50000,
            columns: {
                shipVia: funcs.int({ minValue: 1, maxValue: 3 }),
                freight: funcs.number({ minValue: 0, maxValue: 1000, precision: 100 }),
                shipName: funcs.streetAddress(),
                shipCity: funcs.city(),
                shipRegion: funcs.state(),
                shipPostalCode: funcs.postcode(),
                shipCountry: funcs.country()
            },
            with: {
                details:
                    [
                        { weight: 0.6, count: [1, 2, 3, 4] },
                        { weight: 0.2, count: [5, 6, 7, 8, 9, 10] },
                        { weight: 0.15, count: [11, 12, 13, 14, 15, 16, 17] },
                        { weight: 0.05, count: [18, 19, 20, 21, 22, 23, 24, 25] },
                    ]
            }
        },
        suppliers: {
            count: 1000,
            columns: {
                companyName: funcs.companyName(),
                contactName: funcs.fullName(),
                contactTitle: funcs.jobTitle(),
                address: funcs.streetAddress(),
                city: funcs.city(),
                postalCode: funcs.postcode(),
                region: funcs.state(),
                country: funcs.country(),
                phone: funcs.phoneNumber({ template: "(###) ###-####" })
            }
        },
        products: {
            count: 5000,
            columns: {
                name: funcs.companyName(),
                quantityPerUnit: funcs.valuesFromArray({ values: quantityPerUnit }),
                unitPrice: funcs.weightedRandom(
                    [
                        {
                            weight: 0.5,
                            value: funcs.int({ minValue: 3, maxValue: 300 })
                        },
                        {
                            weight: 0.5,
                            value: funcs.number({ minValue: 3, maxValue: 300, precision: 100 })
                        }
                    ]
                ),
                unitsInStock: funcs.int({ minValue: 0, maxValue: 125 }),
                unitsOnOrder: funcs.valuesFromArray({ values: unitsOnOrders }),
                reorderLevel: funcs.valuesFromArray({ values: reorderLevels }),
                discontinued: funcs.int({ minValue: 0, maxValue: 1 })
            }
        },
        details: {
            columns: {
                unitPrice: funcs.number({ minValue: 10, maxValue: 130 }),
                quantity: funcs.int({ minValue: 1, maxValue: 130 }),
                discount: funcs.weightedRandom(
                    [
                        { weight: 0.5, value: funcs.valuesFromArray({ values: discounts }) },
                        { weight: 0.5, value: funcs.default({ defaultValue: 0 }) }
                    ]
                )
            }
        }
    }));
}

main();

```
</Section>
<Section>
```ts
import type { AnyColumn } from "drizzle-orm";
import { int, numeric, singlestoreTable, text, timestamp, varchar } from "drizzle-orm/singlestore-core";

export const customers = singlestoreTable('customer', {
	id: varchar({ length: 256 }).primaryKey(),
	companyName: text().notNull(),
	contactName: text().notNull(),
	contactTitle: text().notNull(),
	address: text().notNull(),
	city: text().notNull(),
	postalCode: text(),
	region: text(),
	country: text().notNull(),
	phone: text().notNull(),
	fax: text(),
});

export const employees = singlestoreTable(
	'employee',
	{
		id: int().primaryKey().autoincrement(),
		lastName: text().notNull(),
		firstName: text(),
		title: text().notNull(),
		titleOfCourtesy: text().notNull(),
		birthDate: timestamp().notNull(),
		hireDate: timestamp().notNull(),
		address: text().notNull(),
		city: text().notNull(),
		postalCode: text().notNull(),
		country: text().notNull(),
		homePhone: text().notNull(),
		extension: int().notNull(),
		notes: text().notNull(),
		reportsTo: int().references((): AnyColumn => employees.id),
		photoPath: text(),
	},
);

export const orders = singlestoreTable('order', {
	id: int().primaryKey().autoincrement(),
	orderDate: timestamp().notNull(),
	requiredDate: timestamp().notNull(),
	shippedDate: timestamp(),
	shipVia: int().notNull(),
	freight: numeric().notNull(),
	shipName: text().notNull(),
	shipCity: text().notNull(),
	shipRegion: text(),
	shipPostalCode: text(),
	shipCountry: text().notNull(),

	customerId: text().notNull().references(() => customers.id, { onDelete: 'cascade' }),

	employeeId: int().notNull().references(() => employees.id, { onDelete: 'cascade' }),
});

export const suppliers = singlestoreTable('supplier', {
	id: int().primaryKey().autoincrement(),
	companyName: text().notNull(),
	contactName: text().notNull(),
	contactTitle: text().notNull(),
	address: text().notNull(),
	city: text().notNull(),
	region: text(),
	postalCode: text().notNull(),
	country: text().notNull(),
	phone: text().notNull(),
});

export const products = singlestoreTable('product', {
	id: int().primaryKey().autoincrement(),
	name: varchar({ length: 255 }).notNull(),
	quantityPerUnit: text().notNull(),
	unitPrice: numeric().notNull(),
	unitsInStock: int().notNull(),
	unitsOnOrder: int().notNull(),
	reorderLevel: int().notNull(),
	discontinued: int().notNull(),

	supplierId: int().notNull().references(() => suppliers.id, { onDelete: 'cascade' }),
});

export const details = singlestoreTable('order_detail', {
	unitPrice: numeric().notNull(),
	quantity: int().notNull(),
	discount: numeric().notNull(),

	orderId: int().notNull().references(() => orders.id, { onDelete: 'cascade' }),

	productId: int().notNull().references(() => products.id, { onDelete: 'cascade' }),
});

```
</Section>
</CodeTabs>

## Limitations

#### Types limitations for `with`

Due to certain TypeScript limitations and the current API in Drizzle, it is not possible to properly infer references between tables, especially when circular dependencies between tables exist.

This means the `with` option will display all tables in the schema, and you will need to manually select the one that has a one-to-many relationship

<Callout title='warning'>
The `with` option works for one-to-many relationships. For example, if you have one `user` and many `posts`, you can use users `with` posts, but you cannot use posts `with` users
</Callout>

#### Type limitations for the third parameter in Drizzle tables:

Currently, we do not have type support for the third parameter in Drizzle tables. While it will work at runtime, it will not function correctly at the type level


Source: https://orm.drizzle.team/docs/singlestore/seed-versioning

import Tab from "@mdx/Tab.astro";
import Tabs from "@mdx/Tabs.astro";
import Callout from "@mdx/Callout.astro";
import TableWrapper from "@mdx/TableWrapper.astro";

# Versioning

`drizzle-seed` uses versioning to manage outputs for static and dynamic data. To ensure true 
determinism, ensure that values remain unchanged when using the same `seed` number. If changes are made to 
static data sources or dynamic data generation logic, the version will be updated, allowing
you to choose between sticking with the previous version or using the latest.

You can upgrade to the latest `drizzle-seed` version for new features, such as additional
generators, while maintaining deterministic outputs with a previous version if needed. This
is particularly useful when you need to rely on existing deterministic data while accessing new functionality.

```ts
await seed(db, schema, { version: '2' });
```

## History
<TableWrapper>
|          api version  |   npm version    |     Changed generators                    |
|  :--------------      | :--------------  | :-------------                            |
|       `v1`            | `0.1.1`          |                                           |
|       `v2`	        | `0.2.1`          |`string()`, `interval({ isUnique: true })` |
|       `v3`            | `0.4.0`          |`hash generating function`    			   |
|       `v4 (LTS) `     | `1.0.0-beta.8`   |`uuid` 								       |
</TableWrapper>

<Callout collapsed="How it works under the hood?">
> This is not an actual API change; it is just an example of how we will proceed with `drizzle-seed` versioning.

For example, `lastName` generator was changed, and new version, `V2`, of this generator became available.

Later, `firstName` generator was changed, making `V3` version of this generator available.

|                  |       `V1`       |      `V2`       |   `V3(latest)`   |
| :--------------: | :--------------: | :-------------: | :--------------: |
| **LastNameGen**  | `LastNameGenV1`  | `LastNameGenV2` |                  |
| **FirstNameGen** | `FirstNameGenV1` |                 | `FirstNameGenV3` |


##### Use the `firstName` generator of version 3 and the `lastName` generator of version 2
```ts
await seed(db, schema);
```

If you are not ready to use latest generator version right away, you can specify max version to use

##### Use the `firstName` generator of version 1 and the `lastName` generator of version 2
```ts
await seed(db, schema, { version: '2' });
```

##### Use the `firstName` generator of version 1 and the `lastName` generator of version 1.
```ts
await seed(db, schema, { version: '1' });
```

</Callout>

## Version 2
#### Unique `interval` generator was changed

<Callout title='Reason for upgrade'>
An older version of the generator could produce intervals like `1 minute 60 seconds` and `2 minutes 0 seconds`, treating them as distinct intervals.
However, when the `1 minute 60 seconds` interval is inserted into a SingleStore database, it is automatically converted to `2 minutes 0 seconds`. As a result, attempting to insert the `2 minutes 0 seconds` interval into a unique column afterwards will cause an error
</Callout>


You will be affected, if you use the unique `interval` generator in your seeding script, as shown in the script below:
```ts
import { binary, char, singlestoreTable, text, varbinary, varchar } from 'drizzle-orm/singlestore-core';
import { drizzle } from 'drizzle-orm/singlestore';
import { seed } from "drizzle-seed";

const intervals = singlestoreTable('intervals', {
	interval1: char({ length: 255 }).unique(),
	interval2: char({ length: 255 }),
	interval3: varchar({ length: 255 }).unique(),
	interval4: varchar({ length: 255 }),
	interval5: binary({ length: 255 }).unique(),
	interval6: binary({ length: 255 }),
	interval7: varbinary({ length: 255 }).unique(),
	interval8: varbinary({ length: 255 }),
	interval9: text(),
});

async function main() {
	const db = drizzle(process.env.DATABASE_URL!);

	await seed(db, { intervals }, { version: '2' }).refine((f) => ({
		intervals: {
			columns: {
				interval: f.interval({ isUnique: true }),
				interval1: f.interval({ isUnique: true }),
				interval2: f.interval({ isUnique: true }),
				interval3: f.interval({ isUnique: true }),
				interval4: f.interval({ isUnique: true }),
				interval5: f.interval({ isUnique: true }),
				interval6: f.interval({ isUnique: true }),
				interval7: f.interval({ isUnique: true }),
				interval8: f.interval({ isUnique: true }),
				interval9: f.interval({ isUnique: true }),
			},
		},
	}));
}

main();

```

#### `string` generators were changed: both non-unique and unique

<Callout title='Reason to upgrade'>
Ability to generate a unique string based on the length of the text column (e.g., `varchar(20)`)
</Callout>

You will be affected, if your table includes a column of a text-like type with a maximum length parameter or a unique column of a text-like type:
```ts
import { binary, char, singlestoreTable, varbinary, varchar } from 'drizzle-orm/singlestore-core';
import { drizzle } from 'drizzle-orm/singlestore';
import { seed } from "drizzle-seed";

const strings = singlestoreTable('strings', {
	string1: char({ length: 255 }).unique(),
	string2: char({ length: 255 }),
	string3: varchar({ length: 255 }).unique(),
	string4: varchar({ length: 255 }),
	string5: binary({ length: 255 }).unique(),
	string6: binary({ length: 255 }),
	string7: varbinary({ length: 255 }).unique(),
	string8: varbinary({ length: 255 }),
});

async function main() {
	const db = drizzle(process.env.DATABASE_URL!);

	await seed(db, { strings });
}

main();

```

You will be affected, if you use the `string` generator in your seeding script, as shown in the script below:
```ts
import { binary, char, singlestoreTable, text, varbinary, varchar } from 'drizzle-orm/singlestore-core';
import { drizzle } from 'drizzle-orm/singlestore';
import { seed } from "drizzle-seed";

const strings = singlestoreTable('strings', {
	string1: char({ length: 255 }).unique(),
	string2: char({ length: 255 }),
	string3: char({ length: 255 }),
	string4: varchar({ length: 255 }).unique(),
	string5: varchar({ length: 255 }),
	string6: varchar({ length: 255 }),
	string7: binary({ length: 255 }).unique(),
	string8: binary({ length: 255 }),
	string9: binary({ length: 255 }),
	string10: varbinary({ length: 255 }).unique(),
	string11: varbinary({ length: 255 }),
	string12: varbinary({ length: 255 }),
	string13: text(),
});

async function main() {
	const db = drizzle(process.env.DATABASE_URL!);

	await seed(db, { strings }).refine((f) => ({
		strings: {
			columns: {
				string1: f.string({ isUnique: true }),
				string2: f.string({ isUnique: true }),
				string3: f.string(),
				string4: f.string({ isUnique: true }),
				string5: f.string({ isUnique: true }),
				string6: f.string(),
				string7: f.string({ isUnique: true }),
				string8: f.string({ isUnique: true }),
				string9: f.string(),
				string10: f.string({ isUnique: true }),
				string11: f.string({ isUnique: true }),
				string12: f.string(),
				string13: f.string({ isUnique: true }),
			},
		},
	}));
}

main();
```

## Version 3
#### `hash generating function was changed`

<Callout title='Reason to upgrade'>
The previous version of the hash generating function generated different hashes depending on whether Bun or Node.js was used, and hashes also varied across versions of Node.js.

The new hash generating function will generate the same hash regardless of the version of Node.js or Bun, resulting in deterministic data generation across all versions.
</Callout>

All generators will output different values compared to the previous version, even with the same seed number.

**Usage**
```ts
await seed(db, schema);
// or explicit
await seed(db, schema, { version: '3' });
```

**Switch to the old version**

The previous version of hash generating function is v1.
```ts
await seed(db, schema, { version: '1' });
```
To use the v2 generators while maintaining the v1 hash generating function:
```ts
await seed(db, schema, { version: '2' });
```

## Version 4
#### `uuid` generator was changed

<Callout title='Reason to upgrade'>
UUID values generated by the old version of the `uuid` generator fail Zod’s v4 UUID validation.

example
```ts
import { createSelectSchema } from 'drizzle-zod';
import { seed } from 'drizzle-seed';

await seed(db, { uuidTest: schema.uuidTest }, { count: 1 }).refine((funcs) => ({
		uuidTest: {
			columns: {
				col1: funcs.uuid()
			}
		}
	})
);

const uuidSelectSchema = createSelectSchema(schema.uuidTest);
const res = await db.select().from(schema.uuidTest);
// the line below will throw an error when using old version of uuid generator
uuidSelectSchema.parse(res[0]);
```
</Callout>

**Usage**
```ts
await seed(db, schema);
// or explicit
await seed(db, schema, { version: '4' });
```

**Switch to the old version**

The previous version of `uuid` generator is v1.
```ts
await seed(db, schema, { version: '1' });
```
To use the v2 generators while maintaining the v1 `uuid` generator:
```ts
await seed(db, schema, { version: '2' });
```
To use the v3 generators while maintaining the v1 `uuid` generator:
```ts
await seed(db, schema, { version: '3' });
```


Source: https://orm.drizzle.team/docs/singlestore/select

import CodeTabs from '@mdx/CodeTabs.astro';
import Callout from '@mdx/Callout.astro';
import Section from '@mdx/Section.astro';
import $count from '@mdx/$count.mdx';

# SQL Select
Drizzle provides you the most SQL-like way to fetch data from your database, while remaining type-safe and composable.
It natively supports mostly every query feature and capability of every dialect,
and whatever it doesn't support yet, can be added by the user with the powerful [`sql`](/docs/singlestore/sql) operator.

For the following examples, let's assume you have a `users` table defined like this:

```typescript
import { singlestoreTable, text, int } from 'drizzle-orm/singlestore-core';

export const users = singlestoreTable('users', {
  id: int('id').primaryKey(),
  name: text('name').notNull(),
  age: int('age'),
});
```

### Basic select
Select all rows from a table including all columns:

<Section>
```typescript
const result = await db.select().from(users);
/*
  {
    id: number;
    name: string;
    age: number | null;
  }[]
*/
```
```sql
select `id`, `name`, `age` from `users`;
```
</Section>

Notice that the result type is inferred automatically based on the table definition, including columns nullability.

<Callout type="info">
Drizzle always explicitly lists columns in the `select` clause instead of using `select *`.<br />
This is required internally to guarantee the fields order in the query result, and is also generally considered a good practice.
</Callout>

### Partial select
In some cases, you might want to select only a subset of columns from a table.
You can do that by providing a selection object to the `.select()` method:
<Section>
```typescript copy
const result = await db.select({
  field1: users.id,
  field2: users.name,
}).from(users);

const { field1, field2 } = result[0];
```
```sql
select `id`, `name` from `users`;
```
</Section>

Like in SQL, you can use arbitrary expressions as selection fields, not just table columns:

<Section>
```typescript
const result = await db.select({
  id: users.id,
  lowerName: sql<string>`lower(${users.name})`,
}).from(users);
```
```sql
select `id`, lower(`name`) from `users`;
```
</Section>

<Callout type="warning">
By specifying `sql<string>`, you are telling Drizzle that the **expected** type of the field is `string`.<br />
If you specify it incorrectly (e.g. use `sql<number>` for a field that will be returned as a string), the runtime value won't match the expected type.
Drizzle cannot perform any type casts based on the provided type generic, because that information is not available at runtime.

If you need to apply runtime transformations to the returned value, you can use the [`.mapWith()`](/docs/singlestore/sql#sqlmapwith) method.
</Callout>

<Callout title='Info'>
Starting from `v1.0.0-beta.1` you can use `.as()` for columns:

```ts
const result = await db.select({
  id: users.id,
  lowerName: users.name.as("lower"),
}).from(users);
```
</Callout>

### Conditional select

You can have a dynamic selection object based on some condition:

```typescript
async function selectUsers(withName: boolean) {
  return db
    .select({
      id: users.id,
      ...(withName ? { name: users.name } : {}),
    })
    .from(users);
}

const users = await selectUsers(true);
```

### Distinct select

You can use `.selectDistinct()` instead of `.select()` to retrieve only unique rows from a dataset:
<Section>
```ts
await db.selectDistinct().from(users).orderBy(users.id, users.name);

await db.selectDistinct({ id: users.id }).from(users).orderBy(users.id);
```
```sql
select distinct `id`, `name` from `users` order by `id`, `name`;

select distinct `id` from `users` order by `id`;
```
</Section>

### Advanced select
Powered by TypeScript, Drizzle APIs let you build your select queries in a variety of flexible ways.

Sneak peek of advanced partial select, for more detailed advanced usage examples - see our [dedicated guide](/docs/singlestore/guides/include-or-exclude-columns).

<Callout type='warning'>
`getColumns` available starting from `drizzle-orm@1.0.0-beta.2`(read more [here](/docs/singlestore/upgrade-v1))

If you are on pre-1 version(like `0.45.1`) then use `getTableColumns`
</Callout>

<br/>

<CodeTabs items={["example 1", "example 2", "example 3", "example 4"]}>
```ts
import { getColumns, sql } from 'drizzle-orm';

await db.select({
    ...getColumns(posts),
    titleLength: sql<number>`length(${posts.title})`,
  }).from(posts);
```
```ts
import { getColumns } from 'drizzle-orm';

const { content, ...rest } = getColumns(posts); // exclude "content" column
await db.select({ ...rest }).from(posts); // select all other columns
```
```ts
await db.query.posts.findMany({
  columns: {
    title: true,
  },
});
```
```ts
await db.query.posts.findMany({
  columns: {
    content: false,
  },
});
```
</CodeTabs>

## ---

### Filters

You can filter the query results using the [filter operators](/docs/singlestore/operators) in the `.where()` method:

<Section>
```typescript copy
import { eq, lt, gte, ne } from 'drizzle-orm';

await db.select().from(users).where(eq(users.id, 42));
await db.select().from(users).where(lt(users.id, 42));
await db.select().from(users).where(gte(users.id, 42));
await db.select().from(users).where(ne(users.id, 42));
...
```
```sql
select `id`, `name`, `age` from `users` where `id` = 42;
select `id`, `name`, `age` from `users` where `id` < 42;
select `id`, `name`, `age` from `users` where `id` >= 42;
select `id`, `name`, `age` from `users` where `id` <> 42;
```
</Section>

All filter operators are implemented using the [`sql`](/docs/singlestore/sql) function.
You can use it yourself to write arbitrary SQL filters, or build your own operators.
For inspiration, you can check how the operators provided by Drizzle are [implemented](https://github.com/drizzle-team/drizzle-orm/blob/main/drizzle-orm/src/sql/expressions/conditions.ts).
<Section>
```typescript copy
import { sql } from 'drizzle-orm';

function equals42(col: Column) {
  return sql`${col} = 42`;
}

await db.select().from(users).where(sql`${users.id} < 42`);
await db.select().from(users).where(sql`${users.id} = 42`);
await db.select().from(users).where(equals42(users.id));
await db.select().from(users).where(sql`${users.id} >= 42`);
await db.select().from(users).where(sql`${users.id} <> 42`);
await db.select().from(users).where(sql`lower(${users.name}) = 'aaron'`);
```
```sql
select `id`, `name`, `age` from `users` where `id` < 42;
select `id`, `name`, `age` from `users` where `id` = 42;
select `id`, `name`, `age` from `users` where `id` = 42;
select `id`, `name`, `age` from `users` where `id` >= 42;
select `id`, `name`, `age` from `users` where `id` <> 42;
select `id`, `name`, `age` from `users` where lower(`name`) = 'aaron';
```
</Section>

<Callout type='info'>
All the values provided to filter operators and to the `sql` function are parameterized automatically.
For example, this query:
```ts
await db.select().from(users).where(eq(users.id, 42));
```
will be translated to:
```sql
select `id`, `name`, `age` from `users` where `id` = ?; -- params: [42]
```
</Callout>

Inverting condition with a `not` operator:
<Section>
```typescript copy
import { eq, not, sql } from 'drizzle-orm';

await db.select().from(users).where(not(eq(users.id, 42)));
await db.select().from(users).where(sql`not ${users.id} = 42`);
```
```sql
select `id`, `name`, `age` from `users` where not (`id` = 42);
select `id`, `name`, `age` from `users` where not (`id` = 42);
```
</Section>

<Callout type="info">
You can safely alter schema, rename tables and columns
and it will be automatically reflected in your queries because of template interpolation,
as opposed to hardcoding column or table names when writing raw SQL.
</Callout>

### Combining filters
You can logically combine filter operators with `and()` and `or()` operators:
<Section>
```typescript copy
import { eq, and, sql } from 'drizzle-orm';

await db.select().from(users).where(
  and(
    eq(users.id, 42),
    eq(users.name, 'Dan')
  )
);
await db.select().from(users).where(sql`${users.id} = 42 and ${users.name} = 'Dan'`);
```
```sql
select `id`, `name`, `age` from `users` where `id` = 42 and `name` = 'Dan';
select `id`, `name`, `age` from `users` where `id` = 42 and `name` = 'Dan';
```
</Section>

<Section>
```typescript copy
import { eq, or, sql } from 'drizzle-orm';

await db.select().from(users).where(
  or(
    eq(users.id, 42), 
    eq(users.name, 'Dan')
  )
);
await db.select().from(users).where(sql`${users.id} = 42 or ${users.name} = 'Dan'`);
```
```sql
select `id`, `name`, `age` from `users` where `id` = 42 or `name` = 'Dan';
select `id`, `name`, `age` from `users` where `id` = 42 or `name` = 'Dan';
```
</Section>

### Advanced filters
In combination with TypeScript, Drizzle APIs provide you powerful and flexible ways to combine filters in queries.

Sneak peek of conditional filtering, for more detailed advanced usage examples - see our [dedicated guide](/docs/singlestore/guides/conditional-filters-in-query).
<CodeTabs items={["example 1", "example 2"]}>
```ts
const searchPosts = async (term?: string) => {
  await db
    .select()
    .from(posts)
    .where(term ? like(posts.title, term) : undefined);
};
await searchPosts();
await searchPosts('AI');
```
```ts
const searchPosts = async (filters: SQL[]) => {
  await db
    .select()
    .from(posts)
    .where(and(...filters));
};
const filters: SQL[] = [];
filters.push(like(posts.title, 'AI'));
filters.push(inArray(posts.category, ['Tech', 'Art', 'Science']));
filters.push(gt(posts.views, 200));
await searchPosts(filters);
```
</CodeTabs>

## ---

### Order By
Use `.orderBy()` to add `order by` clause to the query, sorting the results by the specified fields:
<Section>
```typescript
import { asc, desc } from 'drizzle-orm';

await db.select().from(users).orderBy(users.name);
await db.select().from(users).orderBy(desc(users.name));

// order by multiple fields
await db.select().from(users).orderBy(users.name, users.name2);
await db.select().from(users).orderBy(asc(users.name), desc(users.name2));
```
```sql
select `id`, `name`, `age` from `users` order by `name`;
select `id`, `name`, `age` from `users` order by `name` desc;

select `id`, `name`, `age` from `users` order by `name`, `name2`;
select `id`, `name`, `age` from `users` order by `name` asc, `name2` desc;
```
</Section>

### Advanced pagination
Powered by TypeScript, Drizzle APIs let you implement all possible SQL pagination and sorting approaches.

Sneak peek of advanced pagination, for more detailed advanced
usage examples - see our dedicated [limit offset pagination](/docs/singlestore/guides/limit-offset-pagination)
and [cursor pagination](/docs/singlestore/guides/cursor-based-pagination) guides.

<CodeTabs items={["example 1", "example 2", "example 3", "example 4"]}>
```ts
await db
  .select()
  .from(users)
  .orderBy(asc(users.id)) // order by is mandatory
  .limit(4) // the number of rows to return
  .offset(4); // the number of rows to skip
```
```ts
const getUsers = async (page = 1, pageSize = 3) => {
  await db.query.users.findMany({
    orderBy: (users, { asc }) => asc(users.id),
    limit: pageSize,
    offset: (page - 1) * pageSize,
  });
};
await getUsers();
```
```ts
const getUsers = async (page = 1, pageSize = 10) => {
   const sq = db
    .select({ id: users.id })
    .from(users)
    .orderBy(users.id)
    .limit(pageSize)
    .offset((page - 1) * pageSize)
    .as('subquery');
   await db.select().from(users).innerJoin(sq, eq(users.id, sq.id)).orderBy(users.id);
};
```
```ts
const nextUserPage = async (cursor?: number, pageSize = 3) => {
  await db
    .select()
    .from(users)
    .where(cursor ? gt(users.id, cursor) : undefined) // if cursor is provided, get rows after it
    .limit(pageSize) // the number of rows to return
    .orderBy(asc(users.id)); // ordering
};
// pass the cursor of the last row of the previous page (id)
await nextUserPage(3);
```
</CodeTabs>

## ---

### WITH clause

Using the `with` clause can help you simplify complex queries by splitting them into smaller subqueries called common table expressions (CTEs):
<Section>
```typescript copy
const sq = db.$with('sq').as(db.select().from(users).where(eq(users.id, 42)));

const result = await db.with(sq).select().from(sq);
```
```sql
with sq as (select `id`, `name`, `age` from `users` where `id` = 42)
select `id`, `name`, `age` from sq;
```
</Section>

SingleStore doesn't support native `RETURNING`, so `insert`, `update`, and `delete` statements that depend on returning rows are not available inside `with` for this dialect.

To select arbitrary SQL values as fields in a CTE and reference them in other CTEs or in the main query,
you need to add aliases to them:
```typescript copy

const sq = db.$with('sq').as(db.select({ 
  name: sql<string>`upper(${users.name})`.as('name'),
})
.from(users));

const result = await db.with(sq).select({ name: sq.name }).from(sq);
```
If you don't provide an alias, the field type will become `DrizzleTypeError` and you won't be able to reference it in other queries.
If you ignore the type error and still try to use the field,
you will get a runtime error, since there's no way to reference that field without an alias.

### Select from subquery
Just like in SQL, you can embed queries into other queries by using the subquery API:
<Section>
```typescript copy
const sq = db.select().from(users).where(eq(users.id, 42)).as('sq');
const result = await db.select().from(sq);
```
```sql
select `id`, `name`, `age` from (select `id`, `name`, `age` from `users` where `id` = 42) `sq`;
```
</Section>

Subqueries can be used in any place where a table can be used, for example in joins:
<Section>
```typescript copy
const sq = db.select().from(users).where(eq(users.id, 42)).as('sq');
const result = await db.select().from(users).leftJoin(sq, eq(users.id, sq.id));
```
```sql
select `users`.`id`, `users`.`name`, `users`.`age`, `sq`.`id`, `sq`.`name`, `sq`.`age` from `users`
  left join (select `id`, `name`, `age` from `users` where `id` = 42) `sq`
    on `users`.`id` = `sq`.`id`;
```
</Section>

## ---

### Aggregations
With Drizzle, you can do aggregations using functions like `sum`, `count`, `avg`, etc. by
grouping and filtering with `.groupBy()` and `.having()` respectfully, same as you would do in raw SQL:

<Section>
```typescript
import { gt } from 'drizzle-orm';

await db.select({
  age: users.age,
  count: sql<number>`cast(count(${users.id}) as int)`,
})
  .from(users)
  .groupBy(users.age);

await db.select({
  age: users.age,
  count: sql<number>`cast(count(${users.id}) as int)`,
})
  .from(users)
  .groupBy(users.age)
  .having(({ count }) => gt(count, 1));
```
```sql
select `age`, cast(count(`id`) as int)
  from `users`
  group by `age`;

select `age`, cast(count(`id`) as int)
  from `users`
  group by `age`
  having cast(count(`id`) as int) > 1;
```
</Section>

<Callout type="info">
`cast(... as int)` is necessary because `count()` returns `decimal` in SingleStore, which is treated as a string value instead of a number.
Alternatively, you can use [`.mapWith(Number)`](/docs/singlestore/sql#sqlmapwith) to cast the value to a number at runtime.

If you need count aggregation - we recommend using our [`$count`](/docs/singlestore/select#count) API
</Callout>

### Aggregations helpers

Drizzle has a set of wrapped `sql` functions, so you don't need to write
`sql` templates for common cases in your app

<Callout type="info">
 Remember, aggregation functions are often used with the GROUP BY clause of the SELECT statement. 
 So if you are selecting using aggregating functions and other columns in one query, 
 be sure to use the `.groupBy` clause
</Callout>

**count**

Returns the number of values in `expression`.
<Section>
```ts
import { count } from 'drizzle-orm'

await db.select({ value: count() }).from(users);
await db.select({ value: count(users.id) }).from(users);
```
```sql
select count(*) from `users`;
select count(`id`) from `users`;
```
```ts
// It's equivalent to writing
await db.select({ 
  value: sql`count(*)`.mapWith(Number) 
}).from(users);

await db.select({ 
  value: sql`count(${users.id})`.mapWith(Number) 
}).from(users);
```
</Section>

**countDistinct**

Returns the number of non-duplicate values in `expression`.
<Section>
```ts
import { countDistinct } from 'drizzle-orm'

await db.select({ value: countDistinct(users.id) }).from(users);
```
```sql
select count(distinct `id`) from `users`;
```
```ts
// It's equivalent to writing
await db.select({ 
  value: sql`count(${users.id})`.mapWith(Number) 
}).from(users);
```
</Section>

**avg**

Returns the average (arithmetic mean) of all non-null values in `expression`.
<Section>
```ts
import { avg } from 'drizzle-orm'

await db.select({ value: avg(users.id) }).from(users);
```
```sql
select avg(`id`) from `users`;
```
```ts
// It's equivalent to writing
await db.select({ 
  value: sql`avg(${users.id})`.mapWith(String) 
}).from(users);
```
</Section>

**avgDistinct**

Returns the average (arithmetic mean) of all non-null values in `expression`.
<Section>
```ts
import { avgDistinct } from 'drizzle-orm'

await db.select({ value: avgDistinct(users.id) }).from(users);
```
```sql
select avg(distinct `id`) from `users`;
```
```ts
// It's equivalent to writing
await db.select({ 
  value: sql`avg(distinct ${users.id})`.mapWith(String) 
}).from(users);
```
</Section>

**sum**

Returns the sum of all non-null values in `expression`.
<Section>
```ts
import { sum } from 'drizzle-orm'

await db.select({ value: sum(users.id) }).from(users);
```
```sql
select sum(`id`) from `users`;
```
```ts
// It's equivalent to writing
await db.select({ 
  value: sql`sum(${users.id})`.mapWith(String) 
}).from(users);
```
</Section>

**sumDistinct**

Returns the sum of all non-null and non-duplicate values in `expression`.
<Section>
```ts
import { sumDistinct } from 'drizzle-orm'

await db.select({ value: sumDistinct(users.id) }).from(users);
```
```sql
select sum(distinct `id`) from `users`;
```
```ts
// It's equivalent to writing
await db.select({ 
  value: sql`sum(distinct ${users.id})`.mapWith(String) 
}).from(users);
```
</Section>

**max**

Returns the maximum value in `expression`.
<Section>
```ts
import { max } from 'drizzle-orm'

await db.select({ value: max(users.id) }).from(users);
```
```sql
select max(`id`) from `users`;
```
```ts
// It's equivalent to writing
await db.select({ 
  value: sql`max(${expression})`.mapWith(users.id) 
}).from(users);
```
</Section>

**min**

Returns the minimum value in `expression`.
<Section>
```ts
import { min } from 'drizzle-orm'

await db.select({ value: min(users.id) }).from(users);
```
```sql
select min(`id`) from `users`;
```
```ts
// It's equivalent to writing
await db.select({ 
  value: sql`min(${users.id})`.mapWith(users.id) 
}).from(users);
```
</Section>

A more advanced example:

```typescript copy
const orders = sqliteTable('order', {
  id: integer('id').primaryKey(),
  orderDate: integer('order_date', { mode: 'timestamp' }).notNull(),
  requiredDate: integer('required_date', { mode: 'timestamp' }).notNull(),
  shippedDate: integer('shipped_date', { mode: 'timestamp' }),
  shipVia: integer('ship_via').notNull(),
  freight: numeric('freight').notNull(),
  shipName: text('ship_name').notNull(),
  shipCity: text('ship_city').notNull(),
  shipRegion: text('ship_region'),
  shipPostalCode: text('ship_postal_code'),
  shipCountry: text('ship_country').notNull(),
  customerId: text('customer_id').notNull(),
  employeeId: integer('employee_id').notNull(),
});

const details = sqliteTable('order_detail', {
  unitPrice: numeric('unit_price').notNull(),
  quantity: integer('quantity').notNull(),
  discount: numeric('discount').notNull(),
  orderId: integer('order_id').notNull(),
  productId: integer('product_id').notNull(),
});

db
  .select({
    id: orders.id,
    shippedDate: orders.shippedDate,
    shipName: orders.shipName,
    shipCity: orders.shipCity,
    shipCountry: orders.shipCountry,
    productsCount: sql<number>`cast(count(${details.productId}) as int)`,
    quantitySum: sql<number>`sum(${details.quantity})`,
    totalPrice: sql<number>`sum(${details.quantity} * ${details.unitPrice})`,
  })
  .from(orders)
  .leftJoin(details, eq(orders.id, details.orderId))
  .groupBy(orders.id)
  .orderBy(asc(orders.id))
  .all();
```

### $count
<$count />

## ---

## ---


Source: https://orm.drizzle.team/docs/singlestore/set-operations

import CodeTabs from '@mdx/CodeTabs.astro';
import CodeTab from '@mdx/CodeTab.astro';
import Callout from '@mdx/Callout.astro';

# Set Operations

SQL set operations combine the results of multiple query blocks into a single result. 
The SQL standard defines the following three set operations: `UNION`, `INTERSECT`, `EXCEPT`, `UNION ALL`, `INTERSECT ALL`, `EXCEPT ALL`.

### Union
Combine all results from two query blocks into a single result, omitting any duplicates.

Get all names from customers and users tables without duplicates.

<CodeTabs items={["import-pattern", "builder-pattern", "schema.ts"]}>
	<CodeTab>
	```typescript copy
    import { union } from 'drizzle-orm/singlestore-core'
    import { users, customers } from './schema'

    const allNamesForUserQuery = db.select({ name: users.name }).from(users);

    const result = await union(
		allNamesForUserQuery,
		db.select({ name: customers.name }).from(customers)
	).limit(10);
    ```
    ```sql
    (select `name` from `sellers`)
    union
    (select `name` from `customers`)
    limit ?
    ```
	</CodeTab>
    <CodeTab>
    ```ts copy
    import { users, customers } from './schema'

    const result = await db
      .select({ name: users.name })
      .from(users)
      .union(db.select({ name: customers.name }).from(customers))
      .limit(10);
    ```
    ```sql
    (select `name` from `sellers`)
    union
    (select `name` from `customers`)
    limit ?
    ```
    </CodeTab>
    <CodeTab>
	```typescript copy
    import { int, singlestoreTable, text, varchar } from "drizzle-orm/singlestore-core";

    const users = singlestoreTable('sellers', {
        id: int('id').primaryKey(),
        name: varchar('name', { length: 256 }).notNull(),
        address: text('address'),
    });
    
    const customers = singlestoreTable('customers', {
        id: int('id').primaryKey(),
        name: varchar('name', { length: 256 }).notNull(),
        city: text('city'),
        email: varchar('email', { length: 256 }).notNull()
    });
    ```
    </CodeTab>
  </CodeTabs>

### Union All
Combine all results from two query blocks into a single result, with duplicates.

Let's consider a scenario where you have two tables, one representing online sales and the other 
representing in-store sales. In this case, you want to combine the data from both tables into a
single result set. Since there might be duplicate transactions, 
you want to keep all the records and not eliminate duplicates.

<Callout type='warning'>
  UNION ALL with ORDER BY behavior inconsistent with MySQL: SingleStore parses UNION ALL followed by ORDER BY commands differently from MySQL. In SingleStore, the following query is valid. In MySQL, it is invalid.
  </Callout>
  <CodeTabs items={["import-pattern", "builder-pattern", "schema.ts"]}>
	<CodeTab>
	```typescript copy
    import { unionAll } from 'drizzle-orm/singlestore-core'
    import { onlineSales, inStoreSales } from './schema'

    const onlineTransactions = db.select({ transaction: onlineSales.transactionId }).from(onlineSales);
    const inStoreTransactions = db.select({ transaction: inStoreSales.transactionId }).from(inStoreSales);

    const result = await unionAll(onlineTransactions, inStoreTransactions);
    ```
    ```sql
    select `transaction_id` from `online_sales`
    union all
    select `transaction_id` from `in_store_sales`
    ```
    </CodeTab>
    <CodeTab>
    ```ts copy
    import { onlineSales, inStoreSales } from './schema'

    const result = await db
      .select({ transaction: onlineSales.transactionId })
      .from(onlineSales)
      .unionAll(
        db.select({ transaction: inStoreSales.transactionId }).from(inStoreSales)
      );
    ```
    ```sql
    (select `transaction_id` from `online_sales`)
    union all 
    (select `transaction_id` from `in_store_sales`)
    ```
	</CodeTab>
    <CodeTab>
	```typescript copy
    import { int, singlestoreTable, text, timestamp, varchar } from "drizzle-orm/singlestore-core";

    const onlineSales = singlestoreTable('online_sales', {
        transactionId: int('transaction_id').primaryKey(),
        productId: int('product_id').unique(),
        quantitySold: int('quantity_sold'),
        saleDate: timestamp('sale_date', { mode: 'date' }),
    });
    
    const inStoreSales = singlestoreTable('in_store_sales', {
        transactionId: int('transaction_id').primaryKey(),
        productId: int('product_id').unique(),
        quantitySold: int('quantity_sold'),
        saleDate: timestamp('sale_date', { mode: 'date' }),
    });
    ```
    </CodeTab>
  </CodeTabs>

### Intersect
Combine only those rows which the results of two query blocks have in common, omitting any duplicates.

Suppose you have two tables that store information about students' course enrollments. 
You want to find the courses that are common between two different departments,
but you want distinct course names, and you're not interested in counting multiple 
enrollments of the same course by the same student.

In this scenario, you want to find courses that are common between the two departments but don't want 
to count the same course multiple times even if multiple students from the same department are enrolled in it.

<CodeTabs items={["import-pattern", "builder-pattern", "schema.ts"]}>
	<CodeTab>
	```typescript copy
    import { intersect } from 'drizzle-orm/singlestore-core'
    import { depA, depB } from './schema'

    const departmentACourses = db.select({ courseName: depA.courseName }).from(depA);
    const departmentBCourses = db.select({ courseName: depB.courseName }).from(depB);

    const result = await intersect(departmentACourses, departmentBCourses);
    ```
    ```sql
    select `projects_name` from `department_a_projects`
    intersect
    select `projects_name` from `department_b_projects`
    ```
	</CodeTab>
    <CodeTab>
    ```typescript copy
    import { depA, depB } from './schema'

    const result = await db
      .select({ courseName: depA.courseName })
      .from(depA)
      .intersect(db.select({ courseName: depB.courseName }).from(depB));
    ```
    ```sql
    select `projects_name` from `department_a_projects`
    intersect
    select `projects_name` from `department_b_projects`
    ```
    </CodeTab>
    <CodeTab>
	```typescript copy
    import { int, singlestoreTable, varchar } from "drizzle-orm/singlestore-core";

    const depA = singlestoreTable('department_a_courses', {
        studentId: int('student_id'),
        courseName: varchar('course_name', { length: 256 }).notNull(),
    });
    
    const depB = singlestoreTable('department_b_courses', {
        studentId: int('student_id'),
        courseName: varchar('course_name', { length: 256 }).notNull(),
    });
    ```
    </CodeTab>
  </CodeTabs>

### Intersect All
Combine only those rows which the results of two query blocks have in common, with duplicates.

Let's consider a scenario where you have two tables containing data about customer orders, and you want 
to identify products that are ordered by both regular customers and VIP customers. In this case, 
you want to keep track of the quantity of each product, even if it's ordered multiple times by 
different customers.

In this scenario, you want to find products that are ordered by both regular customers and VIP customers, 
but you want to retain the quantity information, even if the same product is ordered multiple 
times by different customers.

Not supported by SingleStore

### Except
For two query blocks A and B, return all results from A which are not also present in B, omitting any duplicates.

Suppose you have two tables that store information about employees' project assignments. 
You want to find the projects that are unique to one department 
and not shared with another department, excluding duplicates.

In this scenario, you want to identify the projects that are exclusive to one department and
not shared with the other department. You don't want to count the same project 
multiple times, even if multiple employees from the same department are assigned to it.

<CodeTabs items={["import-pattern", "builder-pattern", "schema.ts"]}>
	<CodeTab>
	```typescript copy
    import { except } from 'drizzle-orm/singlestore-core'
    import { depA, depB } from './schema'

    const departmentACourses = db.select({ courseName: depA.projectsName }).from(depA);
    const departmentBCourses = db.select({ courseName: depB.projectsName }).from(depB);

    const result = await except(departmentACourses, departmentBCourses);
    ```
    ```sql
    select `projects_name` from `department_a_projects`
    except
    select `projects_name` from `department_b_projects`
    ```
	</CodeTab>
    <CodeTab>
    ```ts copy
    import { depA, depB } from './schema'

    const result = await db
        .select({ courseName: depA.projectsName })
        .from(depA)
        .except(db.select({ courseName: depB.projectsName }).from(depB));
    ```
    ```sql
    select `projects_name` from `department_a_projects`
    except
    select `projects_name` from `department_b_projects`
    ```
    </CodeTab>
    <CodeTab>
	```typescript 
    import { int, singlestoreTable, varchar } from "drizzle-orm/singlestore-core";

    const depA = singlestoreTable('department_a_projects', {
        employeeId: int('employee_id'),
        projectsName: varchar('projects_name', { length: 256 }).notNull(),
    });
    
    const depB = singlestoreTable('department_b_projects', {
        employeeId: int('employee_id'),
        projectsName: varchar('projects_name', { length: 256 }).notNull(),
    });
    ```
    </CodeTab>
  </CodeTabs>

### Except All
For two query blocks A and B, return all results from A which are not also present in B, with duplicates.

Let's consider a scenario where you have two tables containing data about customer orders, and you want to 
identify products that are exclusively ordered by regular customers (without VIP customers). 
In this case, you want to keep track of the quantity of each product, even if it's ordered multiple times by different regular customers.

In this scenario, you want to find products that are exclusively ordered by regular customers and not 
ordered by VIP customers. You want to retain the quantity information, even if the same product is ordered multiple times by different regular customers.

Not supported by SingleStore


Source: https://orm.drizzle.team/docs/singlestore/sql-schema-declaration

import Callout from '@mdx/Callout.astro';
import SimpleLinkCards from '@mdx/SimpleLinkCards.astro';
import CodeTabs from "@mdx/CodeTabs.astro";
import Section from '@mdx/Section.astro';
import Flex from "@mdx/Flex.astro"
import LinksList from "@mdx/LinksList.astro"

# Drizzle schema

Drizzle lets you define a schema in TypeScript with various models and properties supported by the underlying database. 
When you define your schema, it serves as the source of truth for future modifications in queries (using Drizzle-ORM)
and migrations (using Drizzle-Kit).

<Callout> 
If you are using Drizzle-Kit for the migration process, make sure to export all the models defined in your schema files so that Drizzle-Kit can import them and use them in the migration diff process. 
</Callout>

<CodeTabs items={["Using imports", "Using callback", "Using import *"]}>
```ts
import { int, singlestoreTable, varchar } from "drizzle-orm/singlestore-core";

export const usersTable = singlestoreTable("users", {
  id: int().primaryKey().autoincrement(),
  name: varchar({ length: 256 }).notNull(),
  age: int().notNull(),
  email: varchar({ length: 256 }).notNull().unique(),
});
```
```ts
import { singlestoreTable } from "drizzle-orm/singlestore-core";

export const usersTable = singlestoreTable("users", (t) => ({
  id: t.int().primaryKey().autoincrement(),
  name: t.varchar({ length: 256 }).notNull(),
  age: t.int().notNull(),
  email: t.varchar({ length: 256 }).notNull().unique(),
}));
```
```ts
import * as t from "drizzle-orm/singlestore-core";

export const usersTable = t.singlestoreTable("users", {
  id: t.int().primaryKey().autoincrement(),
  name: t.varchar({ length: 256 }).notNull(),
  age: t.int().notNull(),
  email: t.varchar({ length: 256 }).notNull().unique(),
});
```
</CodeTabs>

## Organize your schema files 
You can declare your SQL schema directly in TypeScript either in a single `schema.ts` file,
or you can spread them around — whichever you prefer, all the freedom!

#### Schema in 1 file
The most common way to declare your schema with Drizzle is to put all your tables into one `schema.ts` file.

> Note: You can name your schema file whatever you like. For example, it could be `models.ts`, or something else.

This approach works well if you don't have too many table models defined, or if you're okay with keeping them all in one file

Example:
```plaintext
📦 <project root>
 └ 📂 src
    └ 📂 db
       └ 📜 schema.ts
```

In the `drizzle.config.ts` file, you need to specify the path to your schema file. With this configuration, Drizzle will 
read from the `schema.ts` file and use this information during the migration generation process. For more information 
about the `drizzle.config.ts` file and migrations with Drizzle, please check: [link](/docs/singlestore/drizzle-config-file)
```ts
import { defineConfig } from "drizzle-kit";

export default defineConfig({
  dialect: 'singlestore',
  schema: './src/db/schema.ts'
})
```

#### Schema in multiple files

You can place your Drizzle models — such as tables, enums, sequences, etc. — not only in one file but in any file you prefer. 
The only thing you must ensure is that you export all the models from those files so that the Drizzle kit can import 
them and use them in migrations.

One use case would be to separate each table into its own file.
```plaintext
📦 <project root>
 └ 📂 src
    └ 📂 db
       └ 📂 schema
          ├ 📜 users.ts
          ├ 📜 countries.ts
          ├ 📜 cities.ts
          ├ 📜 products.ts
          ├ 📜 clients.ts
          └ 📜 etc.ts
```

In the `drizzle.config.ts` file, you need to specify the path to your schema folder. With this configuration, Drizzle will 
read from the `schema` folder and find all the files recursively and get all the drizzle tables from there. For more information 
about the `drizzle.config.ts` file and migrations with Drizzle, please check: [link](/docs/singlestore/drizzle-config-file)

```ts
import { defineConfig } from "drizzle-kit";

export default defineConfig({
  dialect: 'singlestore',
  schema: './src/db/schema'
})
```

You can also group them in any way you like, such as creating groups for user-related tables, messaging-related tables, product-related tables, etc. 
```plaintext
📦 <project root>
 └ 📂 src
    └ 📂 db
       └ 📂 schema
          ├ 📜 users.ts
          ├ 📜 messaging.ts
          └ 📜 products.ts
```

## Shape your data schema

Drizzle schema consists of several model types from database you are using. With drizzle you can specify:
- Tables with columns, constraints, etc.
- Schemas, which are equivalent to databases in SingleStore
- Enums
- Views
- etc.

Let's go one by one and check how the schema should be defined with drizzle

#### **Tables and columns declaration** 

A table in Drizzle should be defined with at least 1 column, the same as it should be done in database. There is one important thing to know,
there is no such thing as a common table object in Drizzle. You need to choose the SingleStore table object.

![](@/assets/images/table-structure.svg)

```ts copy
import { singlestoreTable, int } from "drizzle-orm/singlestore-core"

export const users = singlestoreTable('users', {
  id: int()
});
```

By default, Drizzle will use the TypeScript key names for columns in database queries. 
Therefore, the schema and query from the example will generate the SQL query shown below

<Callout>
This example uses a db object, whose initialization is not covered in this part of the documentation. To learn how to connect to the database, please refer to the [Connections Docs](/docs/singlestore/get-started-singlestore)
</Callout>

\
**TypeScript key = database key**
<Section>
```ts
// schema.ts
import { int, singlestoreTable, varchar } from "drizzle-orm/singlestore-core";

export const users = singlestoreTable('users', {
  id: int(),
  first_name: varchar({ length: 256 })
})
```
```ts
// query.ts
await db.select().from(users);
```
```sql
SELECT `id`, `first_name` FROM `users`;
```
</Section>

If you want to use different names in your TypeScript code and in the database, you can use column aliases

<Section>
```ts
// schema.ts
import { int, singlestoreTable, varchar } from "drizzle-orm/singlestore-core";

export const users = singlestoreTable('users', {
  id: int(),
  firstName: varchar('first_name', { length: 256 })
})
```
```ts
// query.ts
await db.select().from(users);
```
```sql
SELECT `id`, `first_name` FROM `users`;
```
</Section>

### Camel and Snake casing

Database model names often use `snake_case` conventions, while in TypeScript, it is common to use `camelCase` for naming models. 
This can lead to a lot of alias definitions in the schema. To address this, Drizzle provides a way to automatically 
map `camelCase` from TypeScript to `snake_case` in the database by including one optional parameter during Drizzle database initialization

For such mapping, you can use the `casing` option in the Drizzle DB declaration. This parameter will 
help you specify the database model naming convention and will attempt to map all JavaScript keys accordingly

<Section>
```ts
// schema.ts
import { int, singlestoreTable, varchar } from "drizzle-orm/singlestore-core";

export const users = singlestoreTable('users', {
  id: int(),
  firstName: varchar({ length: 256 })
})
```
```ts
// db.ts
import { drizzle } from "drizzle-orm/singlestore";

const db = drizzle({ connection: process.env.DATABASE_URL, casing: 'snake_case' })
```
```ts
// query.ts
await db.select().from(users);
```
```sql
SELECT `id`, `first_name` FROM `users`;
```
</Section>

### Advanced

There are a few tricks you can use with Drizzle ORM. As long as Drizzle is entirely in TypeScript files, 
you can essentially do anything you would in a simple TypeScript project with your code.

One common feature is to separate columns into different places and then reuse them. 
For example, consider the `updated_at`, `created_at`, and `deleted_at` columns. Many tables/models may need these 
three fields to track and analyze the creation, deletion, and updates of entities in a system

We can define those columns in a separate file and then import and spread them across all the table objects you have

<Section>
```ts
// columns.helpers.ts
const timestamps = {
  updated_at: timestamp(),
  created_at: timestamp().defaultNow().notNull(),
  deleted_at: timestamp(),
}
```
```ts
// users.sql.ts
export const users = singlestoreTable('users', {
  id: int(),
  ...timestamps
})
```
```ts
// posts.sql.ts
export const posts = singlestoreTable('posts', {
  id: int(),
  ...timestamps
})
```
</Section>

#### **Schemas**

\
In SingleStore, there is an entity called `Schema`, but in SingleStore terms, this is equivalent to a `Database`. 

You can define them with `drizzle-orm` and use them in queries, but they won't be detected by `drizzle-kit` or included in the migration flow

![](@/assets/images/mysql-db-structure.png)

Define the schema you want to manage using Drizzle
```ts
import { singlestoreSchema } from "drizzle-orm/singlestore-core"

export const customSchema = singlestoreSchema('custom');
```

Then place the table inside the schema object
```ts {5-7}
import { int, singlestoreSchema } from "drizzle-orm/singlestore-core";

export const customSchema = singlestoreSchema('custom');

export const users = customSchema.table('users', {
  id: int()
})
```

### Example

Once you know the basics, let's define a schema example for a real project to get a better view and understanding

> All examples will use `generateUniqueString`. The implementation for it will be provided after all the schema examples

```ts copy
import { singlestoreTable as table } from "drizzle-orm/singlestore-core";
import * as t from "drizzle-orm/singlestore-core";
import { AnyMySqlColumn } from "drizzle-orm/singlestore-core";

export const users = table(
  "users",
  {
    id: t.int().primaryKey().autoincrement(),
    firstName: t.varchar("first_name", { length: 256 }),
    lastName: t.varchar("last_name", { length: 256 }),
    email: t.varchar({ length: 256 }).notNull(),
    invitee: t.int().references((): AnyMySqlColumn => users.id),
    role: t.singlestoreEnum(["guest", "user", "admin"]).default("guest"),
  },
  (table) => [
    t.uniqueIndex("email_idx").on(table.email)
  ]
);

export const posts = table(
  "posts",
  {
    id: t.int().primaryKey().autoincrement(),
    slug: t.varchar({ length: 256 }).$default(() => generateUniqueString(16)),
    title: t.varchar({ length: 256 }),
    ownerId: t.int("owner_id").references(() => users.id),
  },
  (table) => [
    t.uniqueIndex("slug_idx").on(table.slug),
    t.index("title_idx").on(table.title),
  ]
);

export const comments = table("comments", {
  id: t.int().primaryKey().autoincrement(),
  text: t.varchar({ length: 256 }),
  postId: t.int("post_id").references(() => posts.id),
  ownerId: t.int("owner_id").references(() => users.id),
});
```

**`generateUniqueString` implementation:**
```ts
function generateUniqueString(length: number = 12): string {
  const characters =
    "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
  let uniqueString = "";

  for (let i = 0; i < length; i++) {
    const randomIndex = Math.floor(Math.random() * characters.length);
    uniqueString += characters[randomIndex];
  }

  return uniqueString;
}
```

#### What's next?
<br/>
<Flex>
  <LinksList 
    title='Manage schema'
    links={[
        ["Column types", "/docs/singlestore/column-types"], 
        ["Indexes and Constraints", "/docs/singlestore/indexes-constraints"],
        ["Database Schemas", "/docs/singlestore/schemas"],
      ]}
  />
  <LinksList 
    title='Zero to Hero'
    links={[
        ["Database connection", "/docs/singlestore/connect-overview"], 
        ["Data querying", "/docs/singlestore/data-querying"], 
        ["Migrations", "/docs/singlestore/migrations"], 
      ]}
  />
</Flex>


Source: https://orm.drizzle.team/docs/singlestore/sql

import Callout from '@mdx/Callout.astro';
import Section from '@mdx/Section.astro';

# Magical `sql` operator 🪄

When working with an ORM library, there may be cases where you find it challenging to write a
specific query using the provided ORM syntax. In such situations, you can resort to using
raw queries, which involve constructing a query as a raw string. However, raw queries often
lack the benefits of type safety and query parameterization.

To address this, many libraries have introduced the concept of an `sql` template. This template 
allows you to write more type-safe and parameterized queries, enhancing the overall safety and 
flexibility of your code. Drizzle, being a powerful ORM library, also supports the sql template.

With Drizzle's `sql` template, you can go even further in crafting queries. If you encounter 
difficulties in writing an entire query using the library's query builder, you can selectively
use the `sql` template within specific sections of the Drizzle query. This flexibility enables you 
to employ the sql template in partial SELECT statements, WHERE clauses, ORDER BY clauses, HAVING
clauses, GROUP BY clauses, and even in relational query builders.

By leveraging the capabilities of the sql template in Drizzle, you can maintain the advantages 
of type safety and query parameterization while achieving the desired query structure and complexity.
This empowers you to create more robust and maintainable code within your application.

## sql`` template

One of the most common usages you may encounter in other ORMs as well 
is the ability to use `sql` queries as-is for raw queries.

```typescript copy
import { sql } from 'drizzle-orm' 

const id = 69;
await db.execute(sql`select * from ${usersTable} where ${usersTable.id} = ${id}`)
```

It will generate the current query

```sql
select * from `users` where `users`.`id` = ?; --> [69]
```

Any tables and columns provided to the sql parameter are automatically mapped to their corresponding SQL 
syntax with escaped names for tables, and the escaped table names are appended to column names. 

Additionally, any dynamic parameters such as `${id}` will be mapped to the `?` placeholder, 
and the corresponding values will be moved to an array of values that are passed separately to the database. 

This approach effectively prevents any potential SQL Injection vulnerabilities.

## `sql<T>`

<Callout type="info" emoji="ℹ️">
    Please note that `sql<T>` does not perform any runtime mapping. The type you define using `sql<T>` is
    purely a helper for Drizzle. It is important to understand that there is no feasible way to 
    determine the exact type dynamically, as SQL queries can be highly versatile and customizable. 
</Callout>

You can define a custom type in Drizzle to be used in places where fields require a specific type other than `unknown`.

This feature is particularly useful in partial select queries, ensuring consistent typing for selected fields:

```typescript
// without sql<T> type defined
const response: { lowerName: unknown }[] = await db.select({
    lowerName: sql`lower(${usersTable.id})`
}).from(usersTable);

// with sql<T> type defined
const response: { lowerName: string }[] = await db.select({
    lowerName: sql<string>`lower(${usersTable.id})`
}).from(usersTable);
```

## `sql``.mapWith()`

For the cases you need to make a runtime mapping for values passed from database driver to drizzle you can use `.mapWith()`

This function accepts different values, that will map response in runtime.

You can replicate a specific column mapping strategy as long as
the interface inside mapWith is the same interface that is implemented by Column.

```typescript
import { singlestoreTable, int, text } from 'drizzle-orm/singlestore-core';

const usersTable = singlestoreTable('users', {
    id: int('id').primaryKey().autoincrement(),
    name: text('name').notNull(),
});

//  at runtime this values will be mapped same as `text` column is mapped in drizzle
sql`...`.mapWith(usersTable.name);
```

You can also pass your own implementation for the `DriverValueDecoder` interface:

```ts 
sql``.mapWith({
	mapFromDriverValue: (value: any) => {
		const mappedValue = value;
		// mapping you want to apply
		return mappedValue;
	},
});
    
// or
sql``.mapWith(Number);
```

## `sql``.as<T>()`

In different cases, it can sometimes be challenging to determine how to name a custom field that you want to use.
You may encounter situations where you need to explicitly specify an alias for a 
field that will be selected. This can be particularly useful when dealing with complex queries. 

To address these scenarios, we have introduced a helpful `.as('alias_name')` helper, which allows 
you to define an alias explicitly. By utilizing this feature, you can provide a clear and meaningful 
name for the field, making your queries more intuitive and readable.

<Section>
```typescript
sql`lower(usersTable.name)`.as('lower_name')
```
```sql
... `usersTable`.`name` as lower_name ...
```
</Section>

## `sql.raw()`

There are cases where you may not need to create parameterized values from input or map tables/columns to escaped ones. 
Instead, you might simply want to generate queries as they are. For such situations, we provide the `sql.raw()` function.

The `sql.raw()` function allows you to include raw SQL statements within your queries without any additional processing or escaping.
This can be useful when you have pre-constructed SQL statements or when you need to incorporate complex or dynamic 
SQL code directly into your queries.

<Section>
```typescript
sql.raw(`select * from users where id = ${12}`);
// vs
sql`select * from users where id = ${12}`;
```
```sql
select * from users where id = 12;
--> vs
select * from users where id = ?; --> [12]
```
</Section>

You can also utilize `sql.raw()` within the sql function, enabling you to include any raw string
without escaping it through the main `sql` template function.

By using `sql.raw()` inside the `sql` function, you can incorporate unescaped raw strings 
directly into your queries. This can be particularly useful when you have specific
SQL code or expressions that should remain untouched by the template function's automatic escaping or modification.

<Section>
```typescript
sql`select * from ${usersTable} where id = ${12}`;
// vs
sql`select * from ${usersTable} where id = ${sql.raw(12)}`;
```
```sql
select * from `users` where id = ?; --> [12]
--> vs
select * from `users` where id = 12;
```
</Section>

## sql.fromList()

The `sql` template generates sql chunks, which are arrays of SQL parts that will be concatenated 
into the query and params after applying the SQL to the database or query in Drizzle.

In certain scenarios, you may need to aggregate these chunks into an array using custom business 
logic and then concatenate them into a single SQL statement that can be passed to the database or query.
For such cases, the fromList function can be quite useful.

The fromList function allows you to combine multiple SQL chunks into a single SQL statement. 
You can use it to aggregate and concatenate the individual SQL parts according to your specific 
requirements and then obtain a unified SQL query that can be executed.

<Section>
```typescript
const sqlChunks: SQL[] = [];

sqlChunks.push(sql`select * from users`);

// some logic

sqlChunks.push(sql` where `);

// some logic

for (let i = 0; i < 5; i++) {
	sqlChunks.push(sql`id = ${i}`);

	if (i === 4) continue;
	sqlChunks.push(sql` or `);
}

const finalSql: SQL = sql.fromList(sqlChunks)
```
```sql
select * from users where id = ? or id = ? or id = ? or id = ? or id = ?; --> [0, 1, 2, 3, 4]
```
</Section>

## sql.join()

Indeed, the `sql.join` function serves a similar purpose to the fromList helper. 
However, it provides additional flexibility when it comes to handling spaces between
SQL chunks or specifying custom separators for concatenating the SQL chunks.

With `sql.join`, you can concatenate SQL chunks together using a specified separator. 
This separator can be any string or character that you want to insert between the chunks. 

This is particularly useful when you have specific requirements for formatting or delimiting 
the SQL chunks. By specifying a custom separator, you can achieve the desired structure and formatting 
in the final SQL query.

<Section>
```typescript
const sqlChunks: SQL[] = [];

sqlChunks.push(sql`select * from users`);

// some logic

sqlChunks.push(sql`where`);

// some logic

for (let i = 0; i < 5; i++) {
	sqlChunks.push(sql`id = ${i}`);

if (i === 4) continue;
    sqlChunks.push(sql`or`);
}

const finalSql: SQL = sql.join(sqlChunks, sql.raw(' '));
```
```sql
select * from users where id = ? or id = ? or id = ? or id = ? or id = ?; --> [0, 1, 2, 3, 4]
```
</Section>

## sql.append()

If you have already generated SQL using the `sql` template, you can achieve the same behavior as `fromList`
by using the append function to directly add a new chunk to the generated SQL.

By using the append function, you can dynamically add additional SQL chunks to the existing SQL string,
effectively concatenating them together. This allows you to incorporate custom logic or business 
rules for aggregating the chunks into the final SQL query.

<Section>
```typescript 
const finalSql = sql`select * from users`;

// some logic

finalSql.append(sql` where `);

// some logic

for (let i = 0; i < 5; i++) {
	finalSql.append(sql`id = ${i}`);

	if (i === 4) continue;
	finalSql.append(sql` or `);
}
```
```sql
select * from users where id = ? or id = ? or id = ? or id = ? or id = ?; --> [0, 1, 2, 3, 4]
```
</Section>

## sql.empty()

By using sql.empty(), you can start with a blank SQL object and then dynamically append SQL chunks to it as needed. This allows you to construct the SQL query incrementally, applying custom logic or conditions to determine the contents of each chunk.

Once you have initialized the SQL object using sql.empty(), you can take advantage of the full range
of sql template features such as parameterization, composition, and escaping. 
This empowers you to construct the SQL query in a flexible and controlled manner, 
adapting it to your specific requirements.

```typescript 
const finalSql = sql.empty();

// some logic

finalSql.append(sql`select * from users`);

// some logic

finalSql.append(sql` where `);

// some logic

for (let i = 0; i < 5; i++) {
	finalSql.append(sql`id = ${i}`);

	if (i === 4) continue;
	finalSql.append(sql` or `);
}
```
```sql
select * from users where id = ? or id = ? or id = ? or id = ? or id = ?; --> [0, 1, 2, 3, 4]
```

## `sql` select

You can use the sql functionality in partial select queries as well. Partial select queries allow you to 
retrieve specific fields or columns from a table rather than fetching the entire row.

For more detailed information about partial select queries, you can refer to the Core API
documentation available at **[Core API docs](/docs/singlestore/select#basic-and-partial-select)**.

**Select different custom fields from table**

Here you can see a usage for **[`sql<T>`](/docs/singlestore/sql#sqlt)**, **[`sql``.mapWith()`](/docs/singlestore/sql#sqlmapwith)**, **[`sql``.as<T>()`](/docs/singlestore/sql#sqlast)**.

<Section>
```typescript copy
import { sql } from 'drizzle-orm'
import { usersTable } from 'schema'

await db.select({
    id: usersTable.id,
    lowerName: sql<string>`lower(${usersTable.name})`,
    aliasedName: sql<string>`lower(${usersTable.name})`.as('aliased_column'),
    count: sql<number>`count(*)`.mapWith(Number) 
}).from(usersTable)
```
```sql
select `id`, lower(`name`), lower(`name`) as `aliased_column`, count(*) from `users`;
```
</Section>

## `sql` in where

Indeed, Drizzle provides a set of available expressions that you can use within the sql template. 
However, it is true that databases often have a wider range of expressions available, 
including those provided through extensions or other means.

To ensure flexibility and enable you to utilize any expressions that are not natively
supported by Drizzle, you have the freedom to write the SQL template
directly using the sql function. This allows you to leverage the full power of
SQL and incorporate any expressions or functionalities specific to your target database.

By using the sql template, you are not restricted to only the predefined expressions in Drizzle. 
Instead, you can express complex queries and incorporate any supported expressions that 
the underlying database system provides.

**Filtering by `id` but with sql**
<Section>
```typescript copy
import { sql } from 'drizzle-orm'
import { usersTable } from 'schema'

const id = 77

await db.select()
        .from(usersTable)
        .where(sql`${usersTable.id} = ${id}`)
```
```sql
select * from `users` where `users`.`id` = ?; --> [ 77 ]
```
</Section>

**Advanced fulltext search where statement**
<Section>
```typescript copy
import { sql } from 'drizzle-orm'
import { usersTable } from 'schema'

const searchPattern = "%Ale%"

await db.select()
        .from(usersTable)
        .where(sql`lower(${usersTable.name}) like lower(${searchPattern})`)
```
```sql
select * from `users` where lower(`users`.`name`) like lower(?); --> [ "%Ale%" ]
```
</Section>

## `sql` in orderBy

The `sql` template can indeed be used in the ORDER BY clause when you need specific functionality for ordering that is not
available in Drizzle, but you prefer not to resort to raw SQL.

<Section>
```typescript copy
import { sql } from 'drizzle-orm'
import { usersTable } from 'schema'

await db.select().from(usersTable).orderBy(sql`${usersTable.id} desc nulls first`)
```
```sql
select * from `users` order by `users`.`id` desc nulls first;
```
</Section>

## `sql` in having and groupBy

The `sql` template can indeed be used in the HAVING and GROUP BY clauses when you need specific functionality for ordering that is not
available in Drizzle, but you prefer not to resort to raw SQL.

<Section>
```typescript copy
import { sql } from 'drizzle-orm'
import { usersTable } from 'schema'

await db.select({ 
    projectId: usersTable.projectId,
    count: sql<number>`count(${usersTable.id})`.mapWith(Number)
}).from(usersTable)
    .groupBy(sql`${usersTable.projectId}`)
    .having(sql`count(${usersTable.id}) > 300`)
```
```sql
select `project_id`, count(`users`.`id`) from users group by `users`.`project_id` having count(`users`.`id`) > 300; 
```
</Section>


Source: https://orm.drizzle.team/docs/singlestore/transactions

# Transactions

SQL transaction is a grouping of one or more SQL statements that interact with a database.
A transaction in its entirety can commit to a database as a single logical unit
or rollback (become undone) as a single logical unit.

Drizzle ORM provides APIs to run SQL statements in transactions:

```ts copy
const db = drizzle(...)

await db.transaction(async (tx) => {
  await tx.update(accounts).set({ balance: sql`${accounts.balance} - 100.00` }).where(eq(users.name, 'Dan'));
  await tx.update(accounts).set({ balance: sql`${accounts.balance} + 100.00` }).where(eq(users.name, 'Andrew'));
});
```

Drizzle ORM supports `savepoints` with nested transactions API:

```ts copy {7-9}
const db = drizzle(...)

await db.transaction(async (tx) => {
  await tx.update(accounts).set({ balance: sql`${accounts.balance} - 100.00` }).where(eq(users.name, 'Dan'));
  await tx.update(accounts).set({ balance: sql`${accounts.balance} + 100.00` }).where(eq(users.name, 'Andrew'));

  await tx.transaction(async (tx2) => {
    await tx2.update(users).set({ name: "Mr. Dan" }).where(eq(users.name, "Dan"));
  });
});
```

You can embed business logic to the transaction and rollback whenever needed:

```ts copy {7}
const db = drizzle(...)

await db.transaction(async (tx) => {
  const [account] = await tx.select({ balance: accounts.balance }).from(accounts).where(eq(users.name, 'Dan'));
  if (account.balance < 100) {
    // This throws an exception that rollbacks the transaction.
    tx.rollback()
  }

  await tx.update(accounts).set({ balance: sql`${accounts.balance} - 100.00` }).where(eq(users.name, 'Dan'));
  await tx.update(accounts).set({ balance: sql`${accounts.balance} + 100.00` }).where(eq(users.name, 'Andrew'));
});
```

You can return values from the transaction:

```ts copy {8}
const db = drizzle(...)

const newBalance: number = await db.transaction(async (tx) => {
  await tx.update(accounts).set({ balance: sql`${accounts.balance} - 100.00` }).where(eq(users.name, 'Dan'));
  await tx.update(accounts).set({ balance: sql`${accounts.balance} + 100.00` }).where(eq(users.name, 'Andrew'));

  const [account] = await tx.select({ balance: accounts.balance }).from(accounts).where(eq(users.name, 'Dan'));
  return account.balance;
});
```

You can use transactions with **[relational queries](/docs/singlestore/rqb-v2)**:

```ts
const db = drizzle({ schema })

await db.transaction(async (tx) => {
  await tx.query.users.findMany({
    with: {
      accounts: true
    }
  });
});
```

We provide dialect-specific transaction configuration APIs:

```ts {6-8}
await db.transaction(
  async (tx) => {
    await tx.update(accounts).set({ balance: sql`${accounts.balance} - 100.00` }).where(eq(users.name, "Dan"));
    await tx.update(accounts).set({ balance: sql`${accounts.balance} + 100.00` }).where(eq(users.name, "Andrew"));
  }, {
    isolationLevel: "read committed",
    accessMode: "read write",
    withConsistentSnapshot: true,
  }
);

interface SingleStoreTransactionConfig {
  isolationLevel?:
    | "read uncommitted"
    | "read committed"
    | "repeatable read"
    | "serializable";
  accessMode?: "read only" | "read write";
  withConsistentSnapshot?: boolean;
}
```


Source: https://orm.drizzle.team/docs/singlestore/typebox-legacy

import Npm from '@mdx/Npm.astro';
import Callout from '@mdx/Callout.astro';

<Callout type="error">
Starting from `drizzle-orm@1.0.0-beta.15`, `drizzle-typebox` has been deprecated in favor of first-class schema generation support within Drizzle ORM itself

You can still use `drizzle-typebox` package but all new update will be added to Drizzle ORM directly

This version of `typebox` is legacy by using `@sinclair/typebox` package
</Callout>

# typebox-legacy

### Install the dependencies
<Npm>
drizzle-orm@rc @sinclair/typebox
</Npm>

### Select schema

Defines the shape of data queried from the database - can be used to validate API responses.

```ts copy
import { int, singlestoreTable, text } from 'drizzle-orm/singlestore-core';
import { createSelectSchema } from 'drizzle-orm/typebox-legacy';
import { Value } from '@sinclair/typebox/value';

const users = singlestoreTable('users', {
  id: int().primaryKey().autoincrement(),
  name: text().notNull(),
  age: int().notNull()
});

const userSelectSchema = createSelectSchema(users);

const rows = await db.select({ id: users.id, name: users.name }).from(users).limit(1);
const parsed: { id: number; name: string; age: number } = Value.Parse(userSelectSchema, rows[0]); // Error: `age` is not returned in the above query

const rows = await db.select().from(users).limit(1);
const parsed: { id: number; name: string; age: number } = Value.Parse(userSelectSchema, rows[0]); // Will parse successfully
```

Column enums are supported through the SingleStore table schema and can be validated with the generated table schemas.

### Insert schema

Defines the shape of data to be inserted into the database - can be used to validate API requests.

```ts copy
import { int, singlestoreTable, text } from 'drizzle-orm/singlestore-core';
import { createInsertSchema } from 'drizzle-orm/typebox-legacy';
import { Value } from '@sinclair/typebox/value';

const users = singlestoreTable('users', {
  id: int().primaryKey().autoincrement(),
  name: text().notNull(),
  age: int().notNull()
});

const userInsertSchema = createInsertSchema(users);

const user = { name: 'John' };
const parsed: { name: string, age: number } = Value.Parse(userInsertSchema, user); // Error: `age` is not defined

const user = { name: 'Jane', age: 30 };
const parsed: { name: string, age: number } = Value.Parse(userInsertSchema, user); // Will parse successfully
await db.insert(users).values(parsed);
```

### Update schema

Defines the shape of data to be updated in the database - can be used to validate API requests.

```ts copy
import { int, singlestoreTable, text } from 'drizzle-orm/singlestore-core';
import { createUpdateSchema } from 'drizzle-orm/typebox-legacy';
import { Value } from '@sinclair/typebox/value';

const users = singlestoreTable('users', {
  id: int().primaryKey().autoincrement(),
  name: text().notNull(),
  age: int().notNull()
});

const userUpdateSchema = createUpdateSchema(users);

const user = { id: 5, name: 'John' };
const parsed: { name?: string | undefined, age?: number | undefined } = Value.Parse(userUpdateSchema, user); // Error: `id` is a generated column, it can't be updated

const user = { age: 35 };
const parsed: { name?: string | undefined, age?: number | undefined } = Value.Parse(userUpdateSchema, user); // Will parse successfully
await db.update(users).set(parsed).where(eq(users.name, 'Jane'));
```

### Refinements

Each create schema function accepts an additional optional parameter that you can used to extend, modify or completely overwite a field's schema. Defining a callback function will extend or modify while providing a Typebox schema will overwrite it.

```ts copy
import { int, json, singlestoreTable, text } from 'drizzle-orm/singlestore-core';
import { createSelectSchema } from 'drizzle-orm/typebox-legacy';
import { Type } from '@sinclair/typebox';
import { Value } from '@sinclair/typebox/value';

const users = singlestoreTable('users', {
  id: int().primaryKey().autoincrement(),
  name: text().notNull(),
  bio: text(),
  preferences: json()
});

const userSelectSchema = createSelectSchema(users, {
  name: (schema) => Type.String({ ...schema, maxLength: 20 }), // Extends schema
  bio: (schema) => Type.String({ ...schema, maxLength: 1000 }), // Extends schema before becoming nullable/optional
  preferences: Type.Object({ theme: Type.String() }) // Overwrites the field, including its nullability
});

const parsed: {
  id: number;
  name: string,
  bio?: string | undefined;
  preferences: {
    theme: string;
  };
} = Value.Parse(userSelectSchema, ...);
```

### Factory functions

For more advanced use cases, you can use the `createSchemaFactory` function.

**Use case: Using an extended Typebox instance**

```ts copy
import { int, singlestoreTable, text } from 'drizzle-orm/singlestore-core';
import { createSchemaFactory } from 'drizzle-orm/typebox';
import { t } from 'elysia'; // Extended Typebox instance

const users = singlestoreTable('users', {
  id: int().primaryKey().autoincrement(),
  name: text().notNull(),
  age: int().notNull()
});

const { createInsertSchema } = createSchemaFactory({ typeboxInstance: t });

const userInsertSchema = createInsertSchema(users, {
  // We can now use the extended instance
  name: (schema) => t.Number({ ...schema }, { error: '`name` must be a string' })
});
```

### Data type reference

```ts
singlestore.boolean();

// Schema
Type.Boolean();
```

```ts
singlestore.date({ mode: 'date' });
singlestore.datetime({ mode: 'date' });
singlestore.timestamp({ mode: 'date' });

// Schema
Type.Date();
```

```ts
singlestore.binary();
singlestore.date({ mode: 'string' });
singlestore.datetime({ mode: 'string' });
singlestore.decimal();
singlestore.time();
singlestore.timestamp({ mode: 'string' });
singlestore.varbinary();

// Schema
Type.String();
```

```ts
singlestore.char({ length: ... });

// Schema
Type.String({ minLength: length, maxLength: length });
```

```ts
singlestore.varchar({ length: ... });

// Schema
Type.String({ maxLength: length });
```

```ts
singlestore.text();

// Schema
Type.String({ maxLength: 65_535 }); // unsigned 16-bit integer limit
```

```ts
singlestore.text({ enum: ... });
singlestore.char({ enum: ... });
singlestore.varchar({ enum: ... });
singlestore.singlestoreEnum(..., ...);

// Schema
Type.Enum(enum);
```

```ts
singlestore.tinyint();

// Schema
Type.Integer({ minimum: -128, maximum: 127 }); // 8-bit integer lower and upper limit
```

```ts
singlestore.tinyint({ unsigned: true });

// Schema
Type.Integer({ minimum: 0, maximum: 255 }); // unsigned 8-bit integer lower and upper limit
```

```ts
singlestore.smallint();

// Schema
Type.Integer({ minimum: -32_768, maximum: 32_767 }); // 16-bit integer lower and upper limit
```

```ts
singlestore.smallint({ unsigned: true });

// Schema
Type.Integer({ minimum: 0, maximum: 65_535 }); // unsigned 16-bit integer lower and upper limit
```

```ts
singlestore.float();

// Schema
Type.Number().min(-8_388_608).max(8_388_607); // 24-bit integer lower and upper limit
```

```ts
singlestore.mediumint();

// Schema
Type.Integer({ minimum: -8_388_608, maximum: 8_388_607 }); // 24-bit integer lower and upper limit
```

```ts
singlestore.float({ unsigned: true });

// Schema
Type.Number({ minimum: 0, maximum: 16_777_215 }); // unsigned 24-bit integer lower and upper limit
```

```ts
singlestore.mediumint({ unsigned: true });

// Schema
Type.Integer({ minimum: 0, maximum: 16_777_215 }); // unsigned 24-bit integer lower and upper limit
```

```ts
singlestore.int();

// Schema
Type.Integer({ minimum: -2_147_483_648, maximum: 2_147_483_647 }); // 32-bit integer lower and upper limit
```

```ts
singlestore.int({ unsigned: true });

// Schema
Type.Integer({ minimum: 0, maximum: 4_294_967_295 }); // unsgined 32-bit integer lower and upper limit
```

```ts
singlestore.double();
singlestore.real();

// Schema
Type.Number({ minimum: -140_737_488_355_328, maximum: 140_737_488_355_327 }); // 48-bit integer lower and upper limit
```

```ts
singlestore.double({ unsigned: true });

// Schema
Type.Numer({ minimum: 0, maximum: 281_474_976_710_655 }); // unsigned 48-bit integer lower and upper limit
```

```ts
singlestore.bigint({ mode: 'number' });

// Schema
Type.Integer({ minimum: -9_007_199_254_740_991, maximum: 9_007_199_254_740_991 }); // Javascript min. and max. safe integers
```

```ts
singlestore.serial();

```

```ts
singlestore.bigint({ mode: 'bigint' });

// Schema
Type.BigInt({ minimum: -9_223_372_036_854_775_808n, maximum: 9_223_372_036_854_775_807n }); // 64-bit integer lower and upper limit
```

```ts
singlestore.bigint({ mode: 'bigint', unsigned: true });

// Schema
Type.BigInt({ minimum: 0, maximum: 18_446_744_073_709_551_615n }); // unsigned 64-bit integer lower and upper limit
```

```ts
singlestore.year();

// Schema
Type.Integer({ minimum: 1_901, maximum: 2_155 });
```

```ts
singlestore.json();

// Schema
Type.Recursive((self) => Type.Union([Type.Union([Type.String(), Type.Number(), Type.Boolean(), Type.Null()]), Type.Array(self), Type.Record(Type.String(), self)]));
```


Source: https://orm.drizzle.team/docs/singlestore/typebox

import Npm from '@mdx/Npm.astro';
import Callout from '@mdx/Callout.astro';

<Callout type="error">
Starting from `drizzle-orm@1.0.0-beta.15`, `drizzle-typebox` has been deprecated in favor of first-class schema generation support within Drizzle ORM itself

You can still use `drizzle-typebox` package but all new update will be added to Drizzle ORM directly

This version of `typebox` is using new `typebox` package
</Callout>

# typebox

#### Install the dependencies
<Npm>
drizzle-orm@rc typebox
</Npm>

Allows you to generate [typebox](https://sinclairzx81.github.io/typebox/#/) schemas from Drizzle ORM schemas

**Features**

- Create a select schema for tables.
- Create insert and update schemas for tables.
- Supported dialect: SingleStore.

#### Usage

```ts
import { int, singlestoreTable, text, timestamp } from 'drizzle-orm/singlestore-core';
import { createInsertSchema, createSelectSchema, createUpdateSchema } from 'drizzle-orm/typebox';
import { Type } from 'typebox';
import { Value } from 'typebox/value';

const users = singlestoreTable('users', {
	id: int('id').primaryKey().autoincrement(),
	name: text('name').notNull(),
	email: text('email').notNull(),
	role: text('role', { enum: ['admin', 'user'] }).notNull(),
	createdAt: timestamp('created_at').notNull().defaultNow(),
});

// Schema for inserting a user - can be used to validate API requests
const insertUserSchema = createInsertSchema(users);

// Schema for updating a user - can be used to validate API requests
const updateUserSchema = createUpdateSchema(users);

// Schema for selecting a user - can be used to validate API responses
const selectUserSchema = createSelectSchema(users);

// Overriding the fields
const insertUserSchema = createInsertSchema(users, {
	role: Type.String(),
});

// Refining the fields - useful if you want to change the fields before they become nullable/optional in the final schema
const insertUserSchema = createInsertSchema(users, {
	id: (schema) => Type.Number({ ...schema, minimum: 0 }),
	role: Type.String(),
});

// Usage

const isUserValid: boolean = Value.Check(insertUserSchema, {
	name: 'John Doe',
	email: 'johndoe@test.com',
	role: 'admin',
});
```


Source: https://orm.drizzle.team/docs/singlestore/update

import Callout from '@mdx/Callout.astro';
import Section from '@mdx/Section.astro';

# SQL Update

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

The object that you pass to `update` should have keys that match column names in your database schema.
Values of `undefined` are ignored in the object: to set a column to `null`, pass `null`.
You can pass SQL as a value to be used in the update object, like this:

```typescript copy
await db.update(users)
  .set({ updatedAt: sql`NOW()` })
  .where(eq(users.name, 'Dan'));
```

### Limit
Use `.limit()` to add `limit` clause to the query - for example:
<Section>
```typescript
await db.update(usersTable).set({ verified: true }).limit(2);
```
```sql
update `users` set `verified` = ? limit ?;
```
</Section>

### Order By
Use `.orderBy()` to add `order by` clause to the query, sorting the results by the specified fields:
<Section>
```typescript
import { asc, desc } from 'drizzle-orm';

await db.update(usersTable).set({ verified: true }).orderBy(usersTable.name);
await db.update(usersTable).set({ verified: true }).orderBy(desc(usersTable.name));

// order by multiple fields
await db.update(usersTable).set({ verified: true }).orderBy(usersTable.name, usersTable.name2);
await db.update(usersTable).set({ verified: true }).orderBy(asc(usersTable.name), desc(usersTable.name2));
```
```sql
update `users` set `verified` = ? order by `name`;
update `users` set `verified` = ? order by `name` desc;

update `users` set `verified` = ? order by `name`, `name2`;
update `users` set `verified` = ? order by `name` asc, `name2` desc;
```
</Section>



Source: https://orm.drizzle.team/docs/singlestore/valibot

import Npm from '@mdx/Npm.astro';
import Callout from '@mdx/Callout.astro';

<Callout type="error">
Starting from `drizzle-orm@1.0.0-beta.15`, `drizzle-valibot` has been deprecated in favor of first-class schema generation support within Drizzle ORM itself

You can still use `drizzle-valibot` package but all new update will be added to Drizzle ORM directly
</Callout>

# valibot

### Install the dependencies

<Npm>
valibot
</Npm>

### Select schema

Defines the shape of data queried from the database - can be used to validate API responses.

```ts copy
import { int, singlestoreTable, text } from 'drizzle-orm/singlestore-core';
import { createSelectSchema } from 'drizzle-orm/valibot';
import { parse } from 'valibot';

const users = singlestoreTable('users', {
  id: int().primaryKey().autoincrement(),
  name: text().notNull(),
  age: int().notNull()
});

const userSelectSchema = createSelectSchema(users);

const rows = await db.select({ id: users.id, name: users.name }).from(users).limit(1);
const parsed: { id: number; name: string; age: number } = parse(userSelectSchema, rows[0]); // Error: `age` is not returned in the above query

const rows = await db.select().from(users).limit(1);
const parsed: { id: number; name: string; age: number } = parse(userSelectSchema, rows[0]); // Will parse successfully
```

Column enums are supported through the SingleStore table schema and can be validated with the generated table schemas.

### Insert schema

Defines the shape of data to be inserted into the database - can be used to validate API requests.

```ts copy
import { int, singlestoreTable, text } from 'drizzle-orm/singlestore-core';
import { createInsertSchema } from 'drizzle-orm/valibot';
import { parse } from 'valibot';

const users = singlestoreTable('users', {
  id: int().primaryKey().autoincrement(),
  name: text().notNull(),
  age: int().notNull()
});

const userInsertSchema = createInsertSchema(users);

const user = { name: 'John' };
const parsed: { name: string, age: number } = parse(userInsertSchema, user); // Error: `age` is not defined

const user = { name: 'Jane', age: 30 };
const parsed: { name: string, age: number } = parse(userInsertSchema, user); // Will parse successfully
await db.insert(users).values(parsed);
```

### Update schema

Defines the shape of data to be updated in the database - can be used to validate API requests.

```ts copy
import { int, singlestoreTable, text } from 'drizzle-orm/singlestore-core';
import { createUpdateSchema } from 'drizzle-orm/valibot';
import { parse } from 'valibot';

const users = singlestoreTable('users', {
  id: int().primaryKey().autoincrement(),
  name: text().notNull(),
  age: int().notNull()
});

const userUpdateSchema = createUpdateSchema(users);

const user = { id: 5, name: 'John' };
const parsed: { name?: string | undefined, age?: number | undefined } = parse(userUpdateSchema, user); // Error: `id` is a generated column, it can't be updated

const user = { age: 35 };
const parsed: { name?: string | undefined, age?: number | undefined } = parse(userUpdateSchema, user); // Will parse successfully
await db.update(users).set(parsed).where(eq(users.name, 'Jane'));
```

### Refinements

Each create schema function accepts an additional optional parameter that you can used to extend, modify or completely overwite a field's schema. Defining a callback function will extend or modify while providing a Valibot schema will overwrite it.

```ts copy
import { int, json, singlestoreTable, text } from 'drizzle-orm/singlestore-core';
import { createSelectSchema } from 'drizzle-orm/valibot';
import { parse, pipe, maxLength, object, string } from 'valibot';

const users = singlestoreTable('users', {
  id: int().primaryKey().autoincrement(),
  name: text().notNull(),
  bio: text(),
  preferences: json()
});

const userSelectSchema = createSelectSchema(users, {
  name: (schema) => pipe(schema, maxLength(20)), // Extends schema
  bio: (schema) => pipe(schema, maxLength(1000)), // Extends schema before becoming nullable/optional
  preferences: object({ theme: string() }) // Overwrites the field, including its nullability
});

const parsed: {
  id: number;
  name: string,
  bio?: string | undefined;
  preferences: {
    theme: string;
  };
} = parse(userSelectSchema, ...);
```

### Data type reference

```ts
singlestore.boolean();

// Schema
boolean();
```

```ts
singlestore.date({ mode: 'date' });
singlestore.datetime({ mode: 'date' });
singlestore.timestamp({ mode: 'date' });

// Schema
date();
```

```ts
singlestore.binary();
singlestore.date({ mode: 'string' });
singlestore.datetime({ mode: 'string' });
singlestore.decimal();
singlestore.time();
singlestore.timestamp({ mode: 'string' });
singlestore.varbinary();

// Schema
string();
```

```ts
singlestore.char({ length: ... });

// Schema
pipe(string(), length(length));
```

```ts
singlestore.varchar({ length: ... });

// Schema
pipe(string(), maxLength(length));
```

```ts
singlestore.text();

// Schema
pipe(string(), maxLength(65_535)); // unsigned 16-bit integer limit
```

```ts
singlestore.text({ enum: ... });
singlestore.char({ enum: ... });
singlestore.varchar({ enum: ... });
singlestore.singlestoreEnum(..., ...);

// Schema
enum(enum);
```

```ts
singlestore.tinyint();

// Schema
pipe(number(), minValue(-128), maxValue(127), int()); // 8-bit integer lower and upper limit
```

```ts
singlestore.tinyint({ unsigned: true });

// Schema
pipe(number(), minValue(0), maxValue(255), int()); // unsigned 8-bit integer lower and upper limit
```

```ts
singlestore.smallint();

// Schema
pipe(number(), minValue(-32_768), maxValue(32_767), int()); // 16-bit integer lower and upper limit
```

```ts
singlestore.smallint({ unsigned: true });

// Schema
pipe(number(), minValue(0), maxValue(65_535), int()); // unsigned 16-bit integer lower and upper limit
```

```ts
singlestore.float();

// Schema
pipe(number(), minValue(-8_388_608), maxValue(8_388_607)); // 24-bit integer lower and upper limit
```

```ts
singlestore.mediumint();

// Schema
pipe(number(), minValue(-8_388_608), maxValue(8_388_607), int()); // 24-bit integer lower and upper limit
```

```ts
singlestore.float({ unsigned: true });

// Schema
pipe(number(), minValue(0), maxValue(16_777_215)); // unsigned 24-bit integer lower and upper limit
```

```ts
singlestore.mediumint({ unsigned: true });

// Schema
pipe(number(), minValue(0), maxValue(16_777_215), int()); // unsigned 24-bit integer lower and upper limit
```

```ts
singlestore.int();

// Schema
pipe(number(), minValue(-2_147_483_648), maxValue(2_147_483_647), int()); // 32-bit integer lower and upper limit
```

```ts
singlestore.int({ unsigned: true });

// Schema
pipe(number(), minValue(0), maxValue(4_294_967_295), int()); // unsgined 32-bit integer lower and upper limit
```

```ts
singlestore.double();
singlestore.real();

// Schema
pipe(number(), minValue(-140_737_488_355_328), maxValue(140_737_488_355_327)); // 48-bit integer lower and upper limit
```

```ts
singlestore.double({ unsigned: true });

// Schema
pipe(number(), minValue(0), maxValue(281_474_976_710_655)); // unsigned 48-bit integer lower and upper limit
```

```ts
singlestore.bigint({ mode: 'number' });

// Schema
pipe(number(), minValue(-9_007_199_254_740_991), maxValue(9_007_199_254_740_991), int()); // Javascript min. and max. safe integers
```

```ts
singlestore.serial();

// Schema
pipe(number(), minValue(0), maxValue(9_007_199_254_740_991), int()); // Javascript max. safe integer
```

```ts
singlestore.bigint({ mode: 'bigint' });

// Schema
pipe(bigint(), minValue(-9_223_372_036_854_775_808n), maxValue(9_223_372_036_854_775_807n)); // 64-bit integer lower and upper limit
```

```ts
singlestore.bigint({ mode: 'bigint', unsigned: true });

// Schema
pipe(bigint(), minValue(0n), maxValue(18_446_744_073_709_551_615n)); // unsigned 64-bit integer lower and upper limit
```

```ts
singlestore.year();

// Schema
pipe(number(), minValue(1_901), maxValue(2_155), int());
```

```ts
singlestore.json();

// Schema
union([union([string(), number(), boolean(), null_()]), array(any()), record(string(), any())]);
```



Source: https://orm.drizzle.team/docs/singlestore/zod

import Npm from '@mdx/Npm.astro';
import Callout from '@mdx/Callout.astro';

<Callout type="error">
Starting from `drizzle-orm@1.0.0-beta.15`, `drizzle-zod` has been deprecated in favor of first-class schema generation support within Drizzle ORM itself

You can still use `drizzle-zod` package but all new update will be added to Drizzle ORM directly
</Callout>

# zod

### Install the dependencies

<Npm>
zod
</Npm>

### Select schema

Defines the shape of data queried from the database - can be used to validate API responses.

```ts copy
import { int, singlestoreTable, text } from 'drizzle-orm/singlestore-core';
import { createSelectSchema } from 'drizzle-orm/zod';

const users = singlestoreTable('users', {
  id: int().primaryKey().autoincrement(),
  name: text().notNull(),
  age: int().notNull()
});

const userSelectSchema = createSelectSchema(users);

const rows = await db.select({ id: users.id, name: users.name }).from(users).limit(1);
const parsed: { id: number; name: string; age: number } = userSelectSchema.parse(rows[0]); // Error: `age` is not returned in the above query

const rows = await db.select().from(users).limit(1);
const parsed: { id: number; name: string; age: number } = userSelectSchema.parse(rows[0]); // Will parse successfully
```

Column enums are supported through the SingleStore table schema and can be validated with the generated table schemas.

### Insert schema

Defines the shape of data to be inserted into the database - can be used to validate API requests.

```ts copy
import { int, singlestoreTable, text } from 'drizzle-orm/singlestore-core';
import { createInsertSchema } from 'drizzle-orm/zod';

const users = singlestoreTable('users', {
  id: int().primaryKey().autoincrement(),
  name: text().notNull(),
  age: int().notNull()
});

const userInsertSchema = createInsertSchema(users);

const user = { name: 'John' };
const parsed: { name: string, age: number } = userInsertSchema.parse(user); // Error: `age` is not defined

const user = { name: 'Jane', age: 30 };
const parsed: { name: string, age: number } = userInsertSchema.parse(user); // Will parse successfully
await db.insert(users).values(parsed);
```

### Update schema

Defines the shape of data to be updated in the database - can be used to validate API requests.

```ts copy
import { int, singlestoreTable, text } from 'drizzle-orm/singlestore-core';
import { createUpdateSchema } from 'drizzle-orm/zod';

const users = singlestoreTable('users', {
  id: int().primaryKey().autoincrement(),
  name: text().notNull(),
  age: int().notNull()
});

const userUpdateSchema = createUpdateSchema(users);

const user = { id: 5, name: 'John' };
const parsed: { name?: string | undefined, age?: number | undefined } = userUpdateSchema.parse(user); // Error: `id` is a generated column, it can't be updated

const user = { age: 35 };
const parsed: { name?: string | undefined, age?: number | undefined } = userUpdateSchema.parse(user); // Will parse successfully
await db.update(users).set(parsed).where(eq(users.name, 'Jane'));
```

### Refinements

Each create schema function accepts an additional optional parameter that you can used to extend, modify or completely overwite a field's schema. Defining a callback function will extend or modify while providing a Zod schema will overwrite it.

```ts copy
import { int, json, singlestoreTable, text } from 'drizzle-orm/singlestore-core';
import { createSelectSchema } from 'drizzle-orm/zod';
import { z } from 'zod/v4';

const users = singlestoreTable('users', {
  id: int().primaryKey(),
  name: text().notNull(),
  bio: text(),
  preferences: json()
});

const userSelectSchema = createSelectSchema(users, {
  name: (schema) => schema.max(20), // Extends schema
  bio: (schema) => schema.max(1000), // Extends schema before becoming nullable/optional
  preferences: z.object({ theme: z.string() }) // Overwrites the field, including its nullability
});

const parsed: {
  id: number;
  name: string,
  bio?: string | undefined;
  preferences: {
    theme: string;
  };
} = userSelectSchema.parse(...);
```

### Factory functions

For more advanced use cases, you can use the `createSchemaFactory` function.

**Use case: Using an extended Zod instance**

```ts copy
import { int, singlestoreTable, text } from 'drizzle-orm/singlestore-core';
import { createSchemaFactory } from 'drizzle-orm/zod';
import { z } from '@hono/zod-openapi'; // Extended Zod instance

const users = singlestoreTable('users', {
  id: int().primaryKey().autoincrement(),
  name: text().notNull(),
  age: int().notNull()
});

const { createInsertSchema } = createSchemaFactory({ zodInstance: z });

const userInsertSchema = createInsertSchema(users, {
  // We can now use the extended instance
  name: (schema) => schema.openapi({ example: 'John' })
});
```

**Use case: Type coercion**

```ts copy
import { singlestoreTable, timestamp } from 'drizzle-orm/singlestore-core';
import { createSchemaFactory } from 'drizzle-orm/zod';
import { z } from 'zod/v4';

const users = singlestoreTable('users', {
  ...,
  createdAt: timestamp().notNull()
});

const { createInsertSchema } = createSchemaFactory({
  // This configuration will only coerce dates. Set `coerce` to `true` to coerce all data types or specify others
  coerce: {
    date: true
  }
});

const userInsertSchema = createInsertSchema(users);
// The above is the same as this:
const userInsertSchema = z.object({
  ...,
  createdAt: z.coerce.date()
});
```

### Data type reference

```ts
singlestore.boolean();

// Schema
z.boolean();
```

```ts
singlestore.date({ mode: 'date' });
singlestore.datetime({ mode: 'date' });
singlestore.timestamp({ mode: 'date' });

// Schema
z.date();
```

```ts
singlestore.binary();
singlestore.date({ mode: 'string' });
singlestore.datetime({ mode: 'string' });
singlestore.decimal();
singlestore.time();
singlestore.timestamp({ mode: 'string' });
singlestore.varbinary();

// Schema
z.string();
```

```ts
singlestore.char({ length: ... });

// Schema
z.string().length(length);
```

```ts
singlestore.varchar({ length: ... });

// Schema
z.string().max(length);
```

```ts
singlestore.text();

// Schema
z.string().max(65_535); // unsigned 16-bit integer limit
```

```ts
singlestore.text({ enum: ... });
singlestore.char({ enum: ... });
singlestore.varchar({ enum: ... });
singlestore.singlestoreEnum(..., ...);

// Schema
z.enum(enum);
```

```ts
singlestore.tinyint();

// Schema
z.number().min(-128).max(127).int(); // 8-bit integer lower and upper limit
```

```ts
singlestore.tinyint({ unsigned: true });

// Schema
z.number().min(0).max(255).int(); // unsigned 8-bit integer lower and upper limit
```

```ts
singlestore.smallint();

// Schema
z.number().min(-32_768).max(32_767).int(); // 16-bit integer lower and upper limit
```

```ts
singlestore.smallint({ unsigned: true });

// Schema
z.number().min(0).max(65_535).int(); // unsigned 16-bit integer lower and upper limit
```

```ts
singlestore.float();

// Schema
z.number().min(-8_388_608).max(8_388_607); // 24-bit integer lower and upper limit
```

```ts
singlestore.mediumint();

// Schema
z.number().min(-8_388_608).max(8_388_607).int(); // 24-bit integer lower and upper limit
```

```ts
singlestore.float({ unsigned: true });

// Schema
z.number().min(0).max(16_777_215); // unsigned 24-bit integer lower and upper limit
```

```ts
singlestore.mediumint({ unsigned: true });

// Schema
z.number().min(0).max(16_777_215).int(); // unsigned 24-bit integer lower and upper limit
```

```ts
singlestore.int();

// Schema
z.number().min(-2_147_483_648).max(2_147_483_647).int(); // 32-bit integer lower and upper limit
```

```ts
singlestore.int({ unsigned: true });

// Schema
z.number().min(0).max(4_294_967_295).int(); // unsgined 32-bit integer lower and upper limit
```

```ts
singlestore.double();
singlestore.real();

// Schema
z.number().min(-140_737_488_355_328).max(140_737_488_355_327); // 48-bit integer lower and upper limit
```

```ts
singlestore.double({ unsigned: true });

// Schema
z.number().min(0).max(281_474_976_710_655); // unsigned 48-bit integer lower and upper limit
```

```ts
singlestore.bigint({ mode: 'number' });

// Schema
z.number().min(-9_007_199_254_740_991).max(9_007_199_254_740_991).int(); // Javascript min. and max. safe integers
```

```ts
singlestore.serial();

// Schema
z.number().min(0).max(9_007_199_254_740_991).int(); // Javascript max. safe integer
```

```ts
singlestore.bigint({ mode: 'bigint' });

// Schema
z.bigint().min(-9_223_372_036_854_775_808n).max(9_223_372_036_854_775_807n); // 64-bit integer lower and upper limit
```

```ts
singlestore.bigint({ mode: 'bigint', unsigned: true });

// Schema
z.bigint().min(0).max(18_446_744_073_709_551_615n); // unsigned 64-bit integer lower and upper limit
```

```ts
singlestore.year();

// Schema
z.number().min(1_901).max(2_155).int();
```

```ts
singlestore.json();

// Schema
z.union([z.union([z.string(), z.number(), z.boolean(), z.null()]), z.record(z.any()), z.array(z.any())]);
```



Source: https://orm.drizzle.team/docs/sqlite/aliases

import Section from '@mdx/Section.astro';

# Aliases
Drizzle supports aliasing for tables, columns, subqueries and CTEs — mapping directly to the SQL `AS` keyword.

### Table aliasing
You can alias tables using the `alias` function. This is useful when you need to join the same table multiple times, 
for example in self-referencing relationships like employees and their managers:

<Section>
```ts copy {9}
import { alias, sqliteTable, integer, text } from 'drizzle-orm/sqlite-core';

const employees = sqliteTable('employees', {
  id: integer().primaryKey({ autoIncrement: true }),
  name: text(),
  managerId: integer('manager_id'),
});

const manager = alias(employees, "manager");

await db.select({
  employeeName: employees.name,
  managerName: manager.name,
})
  .from(employees)
  .leftJoin(manager, eq(employees.managerId, manager.id));
```
```sql
select "employees"."name", "manager"."name"
from "employees"
left join "employees" "manager" on "employees"."manager_id" = "manager"."id";
```
</Section>

### Column aliasing
You can alias columns using the `.as()` method on columns and `sql` expressions.
This maps directly to the SQL `AS` keyword and lets you control the name of a column in the query result:

<Section>
```ts {3}
const result = await db.select({
  id: users.id,
  lowerName: users.name.as("lower_name"),
}).from(users);
```
```sql
select "id", "name" as "lower_name" from "users";
```
</Section>

You can also use `.as()` with `sql` expressions:

<Section>
```ts {3}
const result = await db.select({
  id: users.id,
  lowerName: sql<string>`lower(${users.name})`.as("lower_name"),
}).from(users);
```
```sql
select "id", lower("name") as "lower_name" from "users";
```
</Section>

### Subquery aliasing
When using a subquery as a data source, you must provide an alias using `.as()`. 
This lets you reference the subquery's columns in the outer query:

<Section>
```ts
const sq = db.select().from(users).where(eq(users.id, 42)).as('sq');

const result = await db.select().from(sq);
```
```sql
select "id", "name" from (select "id", "name" from "users" where "users"."id" = 42) "sq";
```
</Section>

Subqueries can also be used in joins:

<Section>
```ts
const sq = db.select().from(users).where(eq(users.id, 42)).as('sq');

const result = await db.select().from(users).leftJoin(sq, eq(users.id, sq.id));
```
```sql
select "users"."id", "users"."name", "sq"."id", "sq"."name"
  from "users"
  left join (select "id", "name" from "users" where "users"."id" = 42) "sq"
    on "users"."id" = "sq"."id"
```
</Section>

### CTE aliasing
Common table expressions (CTEs) are aliased using `db.$with('alias')`. 
The alias name is used to reference the CTE in the main query:

<Section>
```ts
const sq = db.$with('sq').as(db.select().from(users).where(eq(users.id, 42)));

const result = await db.with(sq).select().from(sq);
```
```sql
with "sq" as (select "id", "name" from "users" where "users"."id" = 42)
select "id", "name" from "sq";
```
</Section>

When using `sql` expressions inside a CTE, you need to alias them with `.as()` to be able to reference them in the outer query:

<Section>
```ts
const sq = db.$with('sq').as(db.select({
  name: sql<string>`upper(${users.name})`.as('name'),
}).from(users));

const result = await db.with(sq).select({ name: sq.name }).from(sq);
```
```sql
with "sq" as (select upper("name") as "name" from "users")
select "name" from "sq";
```
</Section>

Source: https://orm.drizzle.team/docs/sqlite/arktype

import Npm from '@mdx/Npm.astro';
import Callout from '@mdx/Callout.astro';

# arktype

### Install the dependencies

<Npm>
arktype
</Npm>

### Select schema

Defines the shape of data queried from the database - can be used to validate API responses.

```ts copy
import { integer, sqliteTable, text } from 'drizzle-orm/sqlite-core';
import { createSelectSchema } from 'drizzle-orm/arktype';
import { ArkErrors } from "arktype";

const users = sqliteTable('users', {
  id: integer().primaryKey({ autoIncrement: true }),
  name: text().notNull(),
  age: integer().notNull()
});

const userSelectSchema = createSelectSchema(users);

const rows = await db.select({ id: users.id, name: users.name }).from(users).limit(1);
const parsed: ArkErrors | { id: number; name: string; age: number } = userSelectSchema(rows[0]); // Error: `age` is not returned in the above query

const rows = await db.select().from(users).limit(1);
const parsed: ArkErrors | { id: number; name: string; age: number } = userSelectSchema(rows[0]); // Will parse successfully
```

Views are also supported.

```ts copy
import { sqliteView } from 'drizzle-orm/sqlite-core';
import { gt } from 'drizzle-orm';
import { createSelectSchema } from 'drizzle-orm/arktype';
import { ArkErrors } from "arktype";

const usersView = sqliteView('users_view').as((qb) => qb.select().from(users).where(gt(users.age, 18)));
const usersViewSchema = createSelectSchema(usersView);
const parsed: ArkErrors | { id: number; name: string; age: number } = usersViewSchema(...);
```

### Insert schema

Defines the shape of data to be inserted into the database - can be used to validate API requests.

```ts copy
import { integer, sqliteTable, text } from 'drizzle-orm/sqlite-core';
import { createInsertSchema } from 'drizzle-orm/arktype';
import { ArkErrors } from "arktype";

const users = sqliteTable('users', {
  id: integer().primaryKey({ autoIncrement: true }),
  name: text().notNull(),
  age: integer().notNull()
});

const userInsertSchema = createInsertSchema(users);

const user = { name: 'John' };
const parsed: ArkErrors | { name: string, age: number } = userInsertSchema(user); // Error: `age` is not defined

const user = { name: 'Jane', age: 30 };
const parsed: ArkErrors | { name: string, age: number } = userInsertSchema(user); // Will parse successfully

if (parsed instanceof ArkErrors) {
  console.error(parsed.summary);
  process.exit(1);
}

await db.insert(users).values(parsed);
```

### Update schema

Defines the shape of data to be updated in the database - can be used to validate API requests.

```ts copy
import { integer, sqliteTable, text } from 'drizzle-orm/sqlite-core';
import { createUpdateSchema } from 'drizzle-orm/arktype';
import { ArkErrors } from 'arktype';

const users = sqliteTable('users', {
  id: integer().primaryKey({ autoIncrement: true }),
  name: text().notNull(),
  age: integer().notNull()
});

const userUpdateSchema = createUpdateSchema(users);

const user = { age: 35 };
const parsed: ArkErrors | { name?: string | undefined, age?: number | undefined } = userUpdateSchema(user); // Will parse successfully

if (parsed instanceof ArkErrors) {
  console.error(parsed.summary);
  process.exit(1);
}

await db.update(users).set(parsed).where(eq(users.name, 'Jane'));
```

### Refinements

Each create schema function accepts an additional optional parameter that you can used to extend, modify or completely overwite a field's schema. Defining a callback function will extend or modify while providing a arktype schema will overwrite it.

```ts copy
import { integer, sqliteTable, text } from 'drizzle-orm/sqlite-core';
import { createSelectSchema } from 'drizzle-orm/arktype';
import { ArkErrors, type } from 'arktype';

const users = sqliteTable('users', {
  id: integer().primaryKey({ autoIncrement: true }),
  name: text().notNull(),
  bio: text(),
  preferences: text({ mode: 'json' })
});

const userSelectSchema = createSelectSchema(users, {
  name: (schema) => schema.atMostLength(20), // Extends schema
  bio: (schema) => type.string.atMostLength(2000), // Extends schema before becoming nullable/optional
  preferences: type({ theme: 'string' }) // Overwrites the field, including its nullability
});

const parsed: ArkErrors | {
  id: number;
  name: string,
  bio: string | null;
  preferences: {
    theme: string;
  };
} = userSelectSchema(...);
```

### Data type reference

```ts
sqlite.integer({ mode: 'boolean' });

// Schema
type.boolean;
```

```ts
sqlite.integer({ mode: 'timestamp' });
sqlite.integer({ mode: 'timestamp_ms' });

// Schema
type.Date;
```

```ts
sqlite.numeric();
sqlite.text({ mode: 'text' });

// Schema
type.string;
```

```ts
sqlite.numeric({ mode: 'number' });

// Schema
type.number.atLeast(-9_007_199_254_740_991).atMost(9_007_199_254_740_991); // Javascript min. and max. safe integers
```

```ts
sqlite.numeric({ mode: 'bigint' });

// Schema
type.bigint.narrow(
  (value, ctx) => value < -9_223_372_036_854_775_808n ? ctx.mustBe('greater than') : value > 9_223_372_036_854_775_807n ? ctx.mustBe('less than') : true
); // 64-bit integer lower and upper limit
```

```ts
sqlite.text({ mode: 'text', length: ... });

// Schema
type.string.atMostLength(length);
```

```ts
sqlite.text({ mode: 'text', enum: ... });

// Schema
type.enumerated(...enum);
```

```ts
sqlite.real();

// Schema
type.number.atLeast(-140_737_488_355_328).atMost(140_737_488_355_327); // 48-bit integer lower and upper limit
```

```ts
sqlite.integer({ mode: 'number' });

// Schema
type.keywords.number.integer.atLeast(-9_007_199_254_740_991).atMost(9_007_199_254_740_991); // Javascript min. and max. safe integers
```

```ts
sqlite.blob({ mode: 'bigint' });

// Schema
type.bigint.narrow(
  (value, ctx) => value < -9_223_372_036_854_775_808n ? ctx.mustBe('greater than') : value > 9_223_372_036_854_775_807n ? ctx.mustBe('less than') : true
); // 64-bit integer lower and upper limit
```

```ts
sqlite.blob({ mode: 'json' });
sqlite.text({ mode: 'json' });

// Schema
type('string | number | boolean | null').or(type('unknown.any[] | Record<string, unknown.any>'));
```

```ts
sqlite.blob({ mode: 'buffer' });

// Schema
type.instanceOf(Buffer);
```



Source: https://orm.drizzle.team/docs/sqlite/batch-api

import Tab from '@mdx/Tab.astro';
import Tabs from '@mdx/Tabs.astro';

# Batch API

Drizzle supports running SQL statements in a batch with SQLite-compatible libSQL and Cloudflare D1 drivers.

**LibSQL Batch API explanation**:
_[source](https://docs.turso.tech/sdk/ts/reference#batch-transactions)_

> With the libSQL client library, a batch is one or more SQL statements executed in order in an implicit transaction.
> If all statements are successful, the transaction is committed. If any statement fails, the transaction is rolled back.

**D1 Batch API explanation**:
_[source](https://developers.cloudflare.com/d1/worker-api/d1-database/#batch)_

> Batching sends multiple SQL statements inside a single call to the database. This can reduce latency from network round trips to D1.

```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),
]);
```

<Tabs items={["libSQL", "D1"]}>
<Tab>
```ts
type BatchResponse = [
  { id: number }[],
  ResultSet,
  { id: number; name: string; verified: number; invitedBy: number | null }[],
  { id: number; name: string; verified: number; invitedBy: number | null }[],
  { id: number; invitedBy: number | null }[],
]
```
</Tab>
<Tab>
```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 }[],
]
```
</Tab>
</Tabs>

All possible builders that can be used inside `db.batch`:

```ts
db.all(),
db.get(),
db.values(),
db.run(),
db.execute(),
db.query.<table>.findMany(),
db.query.<table>.findFirst(),
db.select()...,
db.update()...,
db.delete()...,
db.insert()...,
```


Source: https://orm.drizzle.team/docs/sqlite/cache

import Callout from '@mdx/Callout.astro';
import Npm from '@mdx/Npm.astro';

# Cache

Drizzle sends every query straight to your database by default. There are no hidden actions, no automatic caching 
or invalidation - you'll always see exactly what runs. If you want caching, you must opt in.

By default, Drizzle uses a `explicit` caching strategy (i.e. `global: false`), so nothing is ever cached unless you ask. 
This prevents surprises or hidden performance traps in your application. 
Alternatively, you can flip on `all` caching (`global: true`) so that every select will look in cache first.

## Quickstart

### Upstash integration

Drizzle provides an `upstashCache()` helper out of the box. By default, this uses Upstash Redis with automatic configuration if environment variables are set.

```ts
import { upstashCache } from "drizzle-orm/cache/upstash";
import { drizzle } from "drizzle-orm/...";

const db = drizzle(process.env.DB_URL!, {
  cache: upstashCache({ token: process.env.UPSTASH_TOKEN, url: process.env.UPSTASH_URL }),
});
```

You can also explicitly define your Upstash credentials, enable global caching for all queries by default or pass custom caching options:

```ts
import { upstashCache } from "drizzle-orm/cache/upstash";
import { drizzle } from "drizzle-orm/...";

const db = drizzle(process.env.DB_URL!, {
  cache: upstashCache({
    // 👇 Redis credentials (optional — can also be pulled from env vars)
    url: '<UPSTASH_URL>',
    token: '<UPSTASH_TOKEN>',

    // 👇 Enable caching for all queries by default (optional)
    global: true,

    // 👇 Default cache behavior (optional)
    config: { ex: 60 }
  })
});
```

## Cache config reference

Drizzle supports the following cache config options for Upstash:

```ts
export type CacheConfig = {
  /**
   * Expiration in seconds (positive integer)
   */
  ex?: number;
  /**
   * Set an expiration (TTL or time to live) on one or more fields of a given hash key.
   * Used for HEXPIRE command
   */
  hexOptions?: "NX" | "nx" | "XX" | "xx" | "GT" | "gt" | "LT" | "lt";
};
```

## Cache usage examples

Once you've configured caching, here's how the cache behaves:

**Case 1: Drizzle with `global: false` (default, opt-in caching)**

```ts
import { upstashCache } from "drizzle-orm/cache/upstash";
import { drizzle } from "drizzle-orm/...";

const db = drizzle(process.env.DB_URL!, {
  // 👇 `global: true` is not passed, false by default
  cache: upstashCache({ url: "", token: "" }),
});
```

In this case, the following query won't read from cache

```ts
const res = await db.select().from(users);

// Any mutate operation will still trigger the cache's onMutate handler
// and attempt to invalidate any cached queries that involved the affected tables
await db.insert(users).value({ email: "cacheman@upstash.com" });
```

To make this query read from the cache, call `.$withCache()`

```ts
const res = await db.select().from(users).$withCache();
```

`.$withCache` has a set of options you can use to manage and configure this specific query strategy

```ts
// rewrite the config for this specific query
.$withCache({ config: {} })

// give this query a custom cache key (instead of hashing query+params under the hood)
.$withCache({ tag: 'custom_key' })

// turn off auto-invalidation for this query
// note: this leads to eventual consistency (explained below)
.$withCache({ autoInvalidate: false })
```

<Callout>
**Eventual consistency example**

This example is only relevant if you manually set `autoInvalidate: false`. By default, `autoInvalidate` is enabled. 

You might want to turn off `autoInvalidate` if:
- your data doesn't change often, and slight staleness is acceptable (e.g. product listings, blog posts)
- you handle cache invalidation manually

In those cases, turning it off can reduce unnecessary cache invalidation. However, in most cases, we recommend keeping the default enabled.

Example: Imagine you cache the following query on `usersTable` with a 3-second TTL:

``` ts
const recent = await db
  .select().from(usersTable)
  .$withCache({ config: { ex: 3 }, autoInvalidate: false });
```

If someone runs `db.insert(usersTable)...` the cache won't be invalidated immediately. For up to 3 seconds, you'll keep seeing the old data until it eventually becomes consistent.
</Callout>

**Case 2: Drizzle with `global: true` option**

```ts
import { upstashCache } from "drizzle-orm/cache/upstash";
import { drizzle } from "drizzle-orm/...";

const db = drizzle(process.env.DB_URL!, {
  cache: upstashCache({ url: "", token: "", global: true }),
});
```

In this case, the following query will read from cache

```ts
const res = await db.select().from(users);
```

If you want to disable cache for this specific query, call `.$withCache(false)`

```ts
// disable cache for this query
const res = await db.select().from(users).$withCache(false);
```

You can also use cache instance from a `db` to invalidate specific tables or tags

```ts
// Invalidate all queries that use the `users` table. You can do this with the Drizzle instance.
await db.$cache.invalidate({ tables: users });
// or
await db.$cache.invalidate({ tables: [users, posts] });

// Invalidate all queries that use the `usersTable`. You can do this by using just the table name.
await db.$cache.invalidate({ tables: "usersTable" });
// or
await db.$cache.invalidate({ tables: ["usersTable", "postsTable"] });

// You can also invalidate custom tags defined in any previously executed select queries.
await db.$cache.invalidate({ tags: "custom_key" });
// or
await db.$cache.invalidate({ tags: ["custom_key", "custom_key1"] });
```

## Custom cache

This example shows how to plug in a custom `cache` in Drizzle: you provide functions to fetch data from the cache, store results back into cache, and invalidate entries whenever a mutation runs.

Cache extension provides this set of config options
```ts
export type CacheConfig = {
  /** expire time, in seconds */
  ex?: number;
  /** expire time, in milliseconds */
  px?: number;
  /** Unix time (sec) at which the key will expire */
  exat?: number;
  /** Unix time (ms) at which the key will expire */
  pxat?: number;
  /** retain existing TTL when updating a key */
  keepTtl?: boolean;
  /** options for HEXPIRE (hash-field TTL) */
  hexOptions?: 'NX' | 'XX' | 'GT' | 'LT' | 'nx' | 'xx' | 'gt' | 'lt';
};
```

```ts
const db = drizzle(process.env.DB_URL!, { cache: new TestGlobalCache() });
```

```ts
import Keyv from "keyv";

export class TestGlobalCache extends Cache {
  private globalTtl: number = 1000;
  // This object will be used to store which query keys were used
  // for a specific table, so we can later use it for invalidation.
  private usedTablesPerKey: Record<string, string[]> = {};

  constructor(private kv: Keyv = new Keyv()) {
    super();
  }

  // For the strategy, we have two options:
  // - 'explicit': The cache is used only when .$withCache() is added to a query.
  // - 'all': All queries are cached globally.
  // The default behavior is 'explicit'.
  override strategy(): "explicit" | "all" {
    return "all";
  }

  // This function accepts query and parameters that cached into key param,
  // allowing you to retrieve response values for this query from the cache.
  override async get(key: string): Promise<any[] | undefined> {
    const res = (await this.kv.get(key)) ?? undefined;
    return res;
  }

  // This function accepts several options to define how cached data will be stored:
  // - 'key': A hashed query and parameters.
  // - 'response': An array of values returned by Drizzle from the database.
  // - 'tables': An array of tables involved in the select queries. This information is needed for cache invalidation.
  // - 'isTag': A boolean flag indicating whether this cache entry represents a tag-based query.
  //    When true, the entry is associated with a specific tag rather than table-level invalidation,
  //    allowing you to invalidate cached queries by tag name. See the UpstashCache:
  //    https://github.com/drizzle-team/drizzle-orm/blob/beta/drizzle-orm/src/cache/upstash/cache.ts for an example
  //
  // For example, if a query uses the "users" and "posts" tables, you can store this information. Later, when the app executes
  // any mutation statements on these tables, you can remove the corresponding key from the cache.
  // If you're okay with eventual consistency for your queries, you can skip this option.
  override async put(
    key: string,
    response: any,
    tables: string[],
    isTag: boolean = false,
    config?: CacheConfig,
  ): Promise<void> {
    const ttl = config?.px ?? (config?.ex ? config.ex * 1000 : this.globalTtl);

    await this.kv.set(key, response, ttl);

    for (const table of tables) {
      const keys = this.usedTablesPerKey[table];
      if (keys === undefined) {
        this.usedTablesPerKey[table] = [key];
      } else {
        keys.push(key);
      }
    }
  }

  // This function is called when insert, update, or delete statements are executed.
  // You can either skip this step or invalidate queries that used the affected tables.
  //
  // The function receives an object with two keys:
  // - 'tags': Used for queries labeled with a specific tag, allowing you to invalidate by that tag.
  // - 'tables': The actual tables affected by the insert, update, or delete statements,
  //   helping you track which tables have changed since the last cache update.
  override async onMutate(params: {
    tags: string | string[];
    tables: string | string[] | Table<any> | Table<any>[];
  }): Promise<void> {
    const tagsArray = params.tags
      ? Array.isArray(params.tags)
        ? params.tags
        : [params.tags]
      : [];
    const tablesArray = params.tables
      ? Array.isArray(params.tables)
        ? params.tables
        : [params.tables]
      : [];

    const keysToDelete = new Set<string>();

    for (const table of tablesArray) {
      const tableName = is(table, Table)
        ? getTableName(table)
        : (table as string);
      const keys = this.usedTablesPerKey[tableName] ?? [];
      for (const key of keys) keysToDelete.add(key);
    }

    if (keysToDelete.size > 0 || tagsArray.length > 0) {
      for (const tag of tagsArray) {
        await this.kv.delete(tag);
      }

      for (const key of keysToDelete) {
        await this.kv.delete(key);
        for (const table of tablesArray) {
          const tableName = is(table, Table)
            ? getTableName(table)
            : (table as string);
          this.usedTablesPerKey[tableName] = [];
        }
      }
    }
  }
}
```

## Limitations

#### Queries that won't be handled by the `cache` extension:

- Using cache with raw queries, such as:

```ts
db.all(sql`select 1`);
```

- Using cache with `batch` feature in `d1` and `libsql`

```ts
db.batch([
    db.insert(users).values(...),
    db.update(users).set(...).where()
])
```

- Using cache in transactions
```ts
await db.transaction(async (tx) => {
  await tx.update(accounts).set(...).where(...);
  await tx.update...
});
```

#### Limitations that are temporary and will be handled soon:

- Using cache with Drizzle Relational Queries
```ts
await db.query.users.findMany();
```

- Using cache with `better-sqlite3`, `Durable Objects`, `expo sqlite`
- Using cache with views


Source: https://orm.drizzle.team/docs/sqlite/column-types


import Section from '@mdx/Section.astro';
import Callout from '@mdx/Callout.astro';

Based on the official **[SQLite docs](https://www.sqlite.org/datatype3.html)**,
each value stored in an SQLite database (or manipulated by the database engine)
has one of the following storage classes `NULL`, `INTEGER`, `REAL`, `TEXT` and `BLOB`.

We have native support for all of them, yet if that's not enough for you, feel free to create **[custom types](/docs/sqlite/custom-types)**.

<Callout title='important' type='warning'>
All examples in this part of the documentation do not use database column name aliases, and column names are generated from TypeScript keys. 

You can use database aliases in column names if you want, and you can also use the `casing API` to define a mapping strategy for Drizzle.
You can read more about it [here](/docs/sqlite/sql-schema-declaration#shape-your-data-schema)

</Callout>

### Integer

A signed integer, stored in `0`, `1`, `2`, `3`, `4`, `6`, or `8` bytes depending on the magnitude of the value.

<Section>
```typescript
import { integer, sqliteTable } from "drizzle-orm/sqlite-core";

export const table = sqliteTable('table', {
	id: integer()
});

// you can customize integer mode to be number, boolean, timestamp, timestamp_ms
integer({ mode: 'number' })
integer({ mode: 'boolean' })
integer({ mode: 'timestamp_ms' })
integer({ mode: 'timestamp' }) // Date

```

```sql
CREATE TABLE `table` (
	`id` integer
);
```

</Section>

<Section>
```typescript
// to make integer primary key auto increment
integer({ mode: 'number' }).primaryKey({ autoIncrement: true })
```
```sql
CREATE TABLE `table` (
	`id` integer PRIMARY KEY AUTOINCREMENT
);
```
</Section>

### Real

A floating point value, stored as an `8-byte IEEE` floating point number.

<Section>
```typescript
import { real, sqliteTable } from "drizzle-orm/sqlite-core";

export const table = sqliteTable('table', {
	real: real()
});

```

```sql
CREATE TABLE `table` (
	`real` real
);
```

</Section>

### Text

A text string, stored using the database encoding (`UTF-8`, `UTF-16BE` or `UTF-16LE`).  

<Callout type="info" emoji="ℹ️">
	You can define `{ enum: ["value1", "value2"] }` config to infer `insert` and `select` types, it **won't** check runtime values.
</Callout>

<Section>
```typescript
import { text, sqliteTable } from "drizzle-orm/sqlite-core";

export const table = sqliteTable('table', {
	text: text()
});

// will be inferred as text: "value1" | "value2" | null
text({ enum: ["value1", "value2"] })
text({ mode: 'json' })
text({ mode: 'json' }).$type<{ foo: string }>()
```

```sql
CREATE TABLE `table` (
	`text` text
);
```

</Section>

### Blob

A blob of data, stored exactly as it was input.

<Callout type="info" emoji="ℹ️">
	It's recommended to use `text('', { mode: 'json' })` instead of `blob('', { mode: 'json' })`, 
	because it supports JSON functions:

	All JSON functions currently throw an error if any of their arguments are BLOBs because BLOBs 
	are reserved for a future enhancement in which BLOBs will store the binary encoding for JSON.

	See **https://www.sqlite.org/json1.html**.
</Callout>

<Section>
```typescript
import { blob, sqliteTable } from "drizzle-orm/sqlite-core";

export const table = sqliteTable('table', {
	blob: blob()
});

blob()
blob({ mode: 'buffer' })
blob({ mode: 'bigint' })

blob({ mode: 'json' })
blob({ mode: 'json' }).$type<{ foo: string }>()

```

```sql
CREATE TABLE `table` (
	`blob` blob
);
```

You can specify `.$type<..>()` for blob inference, it **won't** check runtime values. 
It provides compile time protection for default values, insert and select schemas.  

```typescript
// will be inferred as { foo: string }
json: blob({ mode: 'json' }).$type<{ foo: string }>();

// will be inferred as string[]
json: blob({ mode: 'json' }).$type<string[]>();

// won't compile
json: blob({ mode: 'json' }).$type<string[]>().default({});
```

</Section>

### Boolean

SQLite does not have native `boolean` data type, yet you can specify `integer` column to be in a `boolean` mode. 
This allows you to operate boolean values in your code and Drizzle stores them as 0 and 1 integer
values in the database.


<Section>
```typescript
import { integer, sqliteTable } from "drizzle-orm/sqlite-core";

export const table = sqliteTable('table', {
	id: integer({ mode: 'boolean' })
});
```

```sql
CREATE TABLE `table` (
	`id` integer
);
```

</Section>

### Bigint

Since there is no `bigint` data type in SQLite, Drizzle offers a special `bigint` mode for `blob` columns. 
This mode allows you to work with BigInt instances in your code, and Drizzle stores them as blob values in the database.


<Section>
```typescript
import { blob, sqliteTable } from "drizzle-orm/sqlite-core";

export const table = sqliteTable('table', {
	id: blob({ mode: 'bigint' })
});

```

```sql
CREATE TABLE `table` (
	`id` blob
);
```
</Section>

### Numeric

<Section>
```typescript
import { numeric, sqliteTable } from 'drizzle-orm/sqlite-core';

export const table = sqliteTable('table', {
  numeric: numeric(),
  numericNum: numeric({ mode: 'number' }),
  numericBig: numeric({ mode: 'bigint' }),
  numericString: numeric({ mode: 'string' }),
});
```

```sql
CREATE TABLE `table` (
	`numeric` numeric,
	`numericNum` numeric,
	`numericBig` numeric,
	`numericString` numeric
);
```
</Section>

## ---

### Customizing data type
Every column builder has a `.$type()` method, which allows you to customize the data type of the column. This is useful, for example, with unknown or branded types.
```ts
type UserId = number & { __brand: 'user_id' };
type Data = {
	foo: string;
	bar: number;
};

export const users = sqliteTable('users', {
  id: integer().$type<UserId>().primaryKey(),
  jsonField: blob().$type<Data>(),
});
```

### Not null
`NOT NULL` constraint dictates that the associated column may not contain a `NULL` value.
<Section>
```typescript
export const table = sqliteTable('table', { 
	numInt: integer().notNull() 
});
```

```sql
CREATE TABLE table (
	`numInt` integer NOT NULL
);
```
</Section>

### Default value

The `DEFAULT` clause specifies a default value to use for the column if no value
is explicitly provided by the user when doing an `INSERT`.
If there is no explicit `DEFAULT` clause attached to a column definition,
then the default value of the column is `NULL`.

An explicit `DEFAULT` clause may specify that the default value is `NULL`,
a string constant, a blob constant, a signed-number, or any constant expression enclosed in parentheses.

<Section>
```typescript
import { sql } from "drizzle-orm";
import { integer, sqliteTable } from "drizzle-orm/sqlite-core";

export const table = sqliteTable('table', {
	int1: integer().default(42),
	int2: integer().default(sql`(abs(42))`)
});

```
```sql
CREATE TABLE `table` (
	`int1` integer DEFAULT 42,
	`int2` integer DEFAULT (abs(42))
);
```
</Section>

A default value may also be one of the special case-independent keywords `CURRENT_TIME`, `CURRENT_DATE` or `CURRENT_TIMESTAMP`.

<Section>
```typescript
import { sql } from "drizzle-orm";
import { text, sqliteTable } from "drizzle-orm/sqlite-core";

export const table = sqliteTable("table", {
  time: text().default(sql`(CURRENT_TIME)`),
  date: text().default(sql`(CURRENT_DATE)`),
  timestamp: text().default(sql`(CURRENT_TIMESTAMP)`),
});
```

```sql
CREATE TABLE `table` (
	`time` text DEFAULT (CURRENT_TIME),
	`date` text DEFAULT (CURRENT_DATE),
	`timestamp` text DEFAULT (CURRENT_TIMESTAMP)
);
```
</Section>

When using `$default()` or `$defaultFn()`, which are simply different aliases for the same function, 
you can generate defaults at runtime and use these values in all insert queries. 
These functions can assist you in utilizing various implementations such as `uuid`, `cuid`, `cuid2`, and many more.

<Callout type="info" emoji="ℹ️">
	Note: This value does not affect the `drizzle-kit` behavior, it is only used at runtime in `drizzle-orm`
</Callout>

```ts
import { text, sqliteTable } from "drizzle-orm/sqlite-core";
import { createId } from '@paralleldrive/cuid2';

export const table = sqliteTable('table', {
	id: text().$defaultFn(() => createId()),
});
```

When using `$onUpdate()` or `$onUpdateFn()`, which are simply different aliases for the same function, 
you can generate defaults at runtime and use these values in all update queries. 

Adds a dynamic update value to the column. The function will be called when the row is updated, 
and the returned value will be used as the column value if none is provided.
If no default (or $defaultFn) value is provided, the function will be called
when the row is inserted as well, and the returned value will be used as the column value.

<Callout type="info" emoji="ℹ️">
	Note: This value does not affect the `drizzle-kit` behavior, it is only used at runtime in `drizzle-orm`
</Callout>

```ts
import { text, sqliteTable } from "drizzle-orm/sqlite-core";

export const table = sqliteTable('table', {
    alwaysNull: text().$type<string | null>().$onUpdate(() => null),
});
```


Source: https://orm.drizzle.team/docs/sqlite/connect-bun-sqlite

import Npm from "@mdx/Npm.astro";
import Callout from '@mdx/Callout.astro';
import AnchorCards from '@mdx/AnchorCards.astro';
import Steps from '@mdx/Steps.astro';
import WhatsNextSQLite from "@mdx/WhatsNextSQLite.astro";
import Prerequisites from "@mdx/Prerequisites.astro";
import CodeTabs from "@mdx/CodeTabs.astro";

# Drizzle \<\> Bun SQLite

<Prerequisites>
- Database [connection basics](/docs/sqlite/connect-overview) with Drizzle
- Bun - [website](https://bun.sh/docs)
- Bun SQLite driver - [docs](https://bun.sh/docs/api/sqlite)
</Prerequisites>

According to the **[official website](https://bun.sh/)**, Bun is a fast all-in-one JavaScript runtime. 

Drizzle ORM natively supports **[`bun:sqlite`](https://bun.sh/docs/api/sqlite)** module and it's crazy fast 🚀  

We embrace SQL dialects and dialect specific drivers and syntax and unlike any other ORM, 
for synchronous drivers like `bun:sqlite` we have both **async** and **sync** APIs and we mirror most popular 
SQLite-like `all`, `get`, `values` and `run` query methods syntax.

#### Step 1 - Install packages
<Npm>
 drizzle-orm@rc
 -D drizzle-kit@rc
</Npm>

#### Step 2 - Initialize the driver and make a query
```typescript copy
import { drizzle } from 'drizzle-orm/bun-sqlite';

const db = drizzle();

const result = await db.select().from(...);
```

If you need to provide your existing driver:
```typescript copy
import { drizzle } from 'drizzle-orm/bun-sqlite';
import { Database } from 'bun:sqlite';

const sqlite = new Database('sqlite.db');
const db = drizzle({ client: sqlite });

const result = await db.select().from(...);
```

If you want to use **sync** APIs:
```typescript copy
import { drizzle } from 'drizzle-orm/bun-sqlite';
import { Database } from 'bun:sqlite';

const sqlite = new Database('sqlite.db');
const db = drizzle({ client: sqlite });

const result = db.select().from(users).all();
const result = db.select().from(users).get();
const result = db.select().from(users).values();
const result = db.select().from(users).run();
```

#### What's next?

<WhatsNextSQLite/>


Source: https://orm.drizzle.team/docs/sqlite/connect-cloudflare-d1

import Npm from "@mdx/Npm.astro";
import Callout from '@mdx/Callout.astro';
import AnchorCards from '@mdx/AnchorCards.astro';
import Steps from '@mdx/Steps.astro';
import WhatsNextSQLite from "@mdx/WhatsNextSQLite.astro";
import Prerequisites from "@mdx/Prerequisites.astro";
import CodeTabs from "@mdx/CodeTabs.astro";

# Drizzle \<\> Cloudflare D1

<Prerequisites>
- Database [connection basics](/docs/sqlite/connect-overview) with Drizzle
- D1 Database - [website](https://developers.cloudflare.com/d1/)
- D1 driver - [website](https://developers.cloudflare.com/d1/build-with-d1/d1-client-api/)
</Prerequisites>

According to the **[official website](https://developers.cloudflare.com/d1/)**, 
D1 is Cloudflare's first queryable relational database.  
  
Drizzle ORM fully supports the Cloudflare D1 database and Cloudflare Workers environment.
We embrace SQL dialects and dialect specific drivers and syntax and mirror most popular 
SQLite-like `all`, `get`, `values` and `run` query methods syntax.

To setup project for your Cloudflare D1 please refer to **[official docs.](https://developers.cloudflare.com/d1/)**

#### Step 1 - Install packages
<Npm>
 drizzle-orm@rc
 -D drizzle-kit@rc
</Npm>

#### Step 2 - Initialize the driver and make a query

You would need to have either a `wrangler.json` or a `wrangler.toml` file for D1 database and will look something like this:
<CodeTabs items={["wrangler.json", "wrangler.toml"]}>
```json
{
    "name": "YOUR_PROJECT_NAME",
    "main": "src/index.ts",
    "compatibility_date": "2024-09-26",
    "compatibility_flags": [
        "nodejs_compat"
    ],
    "d1_databases": [
        {
            "binding": "BINDING_NAME",
            "database_name": "YOUR_DB_NAME",
            "database_id": "YOUR_DB_ID",
            "migrations_dir": "drizzle/migrations"
        }
    ]
}
```
```toml
name = "YOUR_PROJECT_NAME"
main = "src/index.ts"
compatibility_date = "2022-11-07"
node_compat = true

[[ d1_databases ]]
binding = "BINDING_NAME"
database_name = "YOUR_DB_NAME"
database_id = "YOUR_DB_ID"
migrations_dir = "drizzle/migrations"
```
</CodeTabs>

Make your first D1 query:
```typescript copy
import { drizzle } from 'drizzle-orm/d1';

export interface Env {
  <BINDING_NAME>: D1Database;
}

export default {
  async fetch(request: Request, env: Env) {
    const db = drizzle(env.<BINDING_NAME>);
    const result = await db.select().from(users).all()
    return Response.json(result);
  },
};
```

#### What's next?

<WhatsNextSQLite/>


Source: https://orm.drizzle.team/docs/sqlite/connect-cloudflare-do

import Npm from "@mdx/Npm.astro";
import Callout from '@mdx/Callout.astro';
import AnchorCards from '@mdx/AnchorCards.astro';
import Steps from '@mdx/Steps.astro';
import WhatsNextSQLite from "@mdx/WhatsNextSQLite.astro";
import Prerequisites from "@mdx/Prerequisites.astro";
import CodeTabs from "@mdx/CodeTabs.astro";

# Drizzle \<\> Cloudflare Durable Objects SQLite

<Prerequisites>
- Database [connection basics](/docs/sqlite/connect-overview) with Drizzle
- **Cloudflare SQLite Durable Objects** - SQLite database embedded within a Durable Object - [read here](https://developers.cloudflare.com/durable-objects/best-practices/access-durable-objects-storage/#sqlite-storage-backend)
</Prerequisites>
  
Drizzle ORM fully supports the Cloudflare Durable Objects database and Cloudflare Workers environment.
We embrace SQL dialects and dialect specific drivers and syntax and mirror most popular 
SQLite-like `all`, `get`, `values` and `run` query methods syntax.

To setup project for your Cloudflare Durable Objects please refer to **[official docs.](https://developers.cloudflare.com/durable-objects)**

#### Step 1 - Install packages
<Npm>
 drizzle-orm@rc
 -D drizzle-kit@rc
</Npm>

#### Step 2 - Initialize the driver and make a query

You would need to have a `wrangler.toml` file for Durable Objects database and will look something like this:
```toml {16-18,21-24}
#:schema node_modules/wrangler/config-schema.json
name = "sqlite-durable-objects"
main = "src/index.ts"
compatibility_date = "2024-11-12"
compatibility_flags = [ "nodejs_compat" ]

# Bind a Durable Object. Durable objects are a scale-to-zero compute primitive based on the actor model.
# Durable Objects can live for as long as needed. Use these when you need a long-running "server", such as in realtime apps.
# Docs: https://developers.cloudflare.com/workers/wrangler/configuration/#durable-objects
[[durable_objects.bindings]]
name = "MY_DURABLE_OBJECT"
class_name = "MyDurableObject"

# Durable Object migrations.
# Docs: https://developers.cloudflare.com/workers/wrangler/configuration/#migrations
[[migrations]]
tag = "v1"
new_sqlite_classes = ["MyDurableObject"]

# We need rules so we can import migrations in the next steps
[[rules]] 
type = "Text"
globs = ["**/*.sql"]
fallthrough = true
```

Make your first Durable Objects SQLite query:
```typescript copy
/// <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 MyDurableObject 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 });

		// Make sure all migrations complete before accepting queries.
		// Otherwise you will need to run `this.migrate()` in any function
		// that accesses the Drizzle database `this.db`.
		ctx.blockConcurrencyWhile(async () => {
			await this._migrate();
		});
	}

	async insertAndList(user: typeof usersTable.$inferInsert) {
		await this.insert(user);
		return this.select();
	}

	async insert(user: typeof usersTable.$inferInsert) {
		await this.db.insert(usersTable).values(user);
	}

	async select() {
		return this.db.select().from(usersTable);
	}

	async _migrate() {
		migrate(this.db, migrations);
	}
}

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_OBJECT.idFromName('durable-object');
		const stub = env.MY_DURABLE_OBJECT.get(id);

		// Option A - Maximum performance.
		// Prefer to bundle all the database interaction within a single Durable Object call
		// for maximum performance, since database access is fast within a DO.
		const usersAll = await stub.insertAndList({
			name: 'John',
			age: 30,
			email: 'john@example.com',
		});
		console.log('New user created. Getting all users from the database: ', users);

		// Option B - Slow but maybe useful sometimes for debugging.
		// You can also directly call individual Drizzle queries if they are exposed
		// but keep in mind every query is a round-trip to the Durable Object instance.
		await stub.insert({
			name: 'John',
			age: 30,
			email: 'john@example.com',
		});
		console.log('New user created!');
	
		const users = await stub.select();
		console.log('Getting all users from the database: ', users);

		return Response.json(users);
	}
}
```

#### What's next?

<WhatsNextSQLite/>


Source: https://orm.drizzle.team/docs/sqlite/connect-drizzle-proxy

import Npm from "@mdx/Npm.astro";
import Callout from '@mdx/Callout.astro';
import Steps from '@mdx/Steps.astro';
import AnchorCards from '@mdx/AnchorCards.astro';
import Prerequisites from "@mdx/Prerequisites.astro";
import Section from "@mdx/Section.astro";

# Drizzle HTTP proxy

<Prerequisites>
- Database [connection basics](/docs/sqlite/connect-overview) with Drizzle
</Prerequisites>

How an HTTP Proxy works and why you might need it

Drizzle Proxy is used when you need to implement your own driver communication with the database. 
It can be used in several cases, such as adding custom logic at the query stage with existing drivers. 
The most common use is with an HTTP driver, which sends queries to your server with the database, executes the query 
on your database, and responds with raw data that Drizzle ORM can then map to results

<Callout collapsed="How it works under the hood?">
```                                  
┌───────────────────────────┐                 ┌─────────────────────────────┐              
│       Drizzle ORM         │                 │  HTTP Server with Database  │             
└─┬─────────────────────────┘                 └─────────────────────────┬───┘             
  │                                                ^                    │
  │-- 1. Build query         2. Send built query --│                    │
  │                                                │                    │
  │              ┌───────────────────────────┐     │                    │
  └─────────────>│                           │─────┘                    │ 
                 │      HTTP Proxy Driver    │                          │
  ┌──────────────│                           │<─────────────┬───────────┘
  │              └───────────────────────────┘              │
  │                                                  3. Execute a query + send raw results back
  │-- 4. Map data and return        
  │                   
  v
```
</Callout>

Drizzle ORM also supports simply using asynchronous callback function for executing SQL.

- `sql` is a query string with placeholders.
- `params` is an array of parameters.
- One of the following values will set for `method` depending on the SQL statement - `run`, `all`, `values` or `get`.

Drizzle always waits for `{rows: string[][]}` or `{rows: string[]}` for the return value.

- When the `method` is `get`, you should return a value as `{rows: string[]}`.
- Otherwise, you should return `{rows: string[][]}`.

<br/>

<Section>
```typescript copy
import { drizzle } from 'drizzle-orm/sqlite-proxy';
import axios from 'axios';

const db = drizzle(async (sql, params, method) => {
  try {
    const rows = await axios.post('http://localhost:3000/query', { sql, params, method });

    return { rows: rows.data };
  } catch (e: any) {
    console.error('Error from sqlite proxy server: ', e.response.data)
    return { rows: [] };
  }
});
```

**Batch support**

Sqlite Proxy supports batch requests, the same as it's done for all other drivers. Check full [docs](/docs/sqlite/batch-api)

You will need to specify a specific callback for batch queries and handle requests to proxy server:

```ts
import { drizzle } from 'drizzle-orm/sqlite-proxy';
import axios from 'axios';

type ResponseType = { rows: any[][] | any[] }[];

const db = drizzle(async (sql, params, method) => {
  // single queries logic. Same as in code above
}, async (queries: { sql: string, params: any[], method: 'all' | 'run' | 'get' | 'values'}[]) => {
    try {
      const result: ResponseType = await axios.post('http://localhost:3000/batch', { queries });

      return result;
    } catch (e: any) {
      console.error('Error from sqlite proxy server:', e);
      throw e;
    }
  });
```

And then you can use `db.batch([])` method, that will proxy all queries

<Callout>
  Response from the batch should be an array of raw values (an array within an array), in the same order as they were sent to the proxy server
</Callout>

Unless you plan on writing every SQL query by hand, a table declaration is helpful:
```typescript copy
import { sql } from "drizzle-orm";
import { text, integer, sqliteTable } from "drizzle-orm/sqlite-core";

const users = sqliteTable('users', {
  id: text('id'),
  textModifiers: text('text_modifiers').notNull().default(sql`CURRENT_TIMESTAMP`),
  intModifiers: integer('int_modifiers', { mode: 'boolean' }).notNull().default(false),
});
```
For more details about column types, see the **[SQLite column types in Drizzle.](/docs/sqlite/column-types)**
</Section>


Source: https://orm.drizzle.team/docs/sqlite/connect-expo-sqlite

import Npm from "@mdx/Npm.astro";
import Callout from '@mdx/Callout.astro';
import AnchorCards from '@mdx/AnchorCards.astro';
import Steps from '@mdx/Steps.astro';


# Drizzle \<\> Expo SQLite
According to the **[official website](https://expo.dev/)**, Expo is an ecosystem of tools to develop, build and ship applications on React Native. 
It's powered by Hermes JavaScript runtime and Metro bundler, Drizzle Expo driver is built to natively support both.  
  
Drizzle ORM has the best in class toolkit for Expo SQLite:
- Native ORM driver for Expo SQLite ✅
- [Drizzle Kit](/docs/sqlite/kit-overview) support for migration generation and bundling in application ✅
- [Drizzle Studio](https://github.com/drizzle-team/drizzle-studio-expo) dev tools plugin to browse on device database ✅
- Live Queries ✅
  
<Npm>
 drizzle-orm@rc expo-sqlite@next
 -D drizzle-kit@rc
</Npm>

```ts
import { drizzle } from "drizzle-orm/expo-sqlite";
import { openDatabaseSync } from "expo-sqlite";

const expo = openDatabaseSync("db.db");
const db = drizzle(expo);

await db.select().from(users);
```
#### Live Queries
With `useLiveQuery` hook you can make any Drizzle query reactive:
```ts
import { useLiveQuery, drizzle } from 'drizzle-orm/expo-sqlite';
import { openDatabaseSync } from 'expo-sqlite';
import { Text } from 'react-native';
import * as schema from './schema';

const expo = openDatabaseSync('db.db', { enableChangeListener: true }); // <-- enable change listeners
const db = drizzle(expo);

const App = () => {
  // Re-renders automatically when data changes
  const { data } = useLiveQuery(db.select().from(schema.users));
  return <Text>{JSON.stringify(data)}</Text>;
};

export default App;
```

#### Expo SQLite migrations with Drizzle Kit
You can use Drizzle Kit for SQL migration generation.  
Please make sure to check how [Drizzle migrations](/docs/sqlite/kit-overview) work before proceeding.  
Expo / React Native requires you to have SQL migrations bundled into the app and we've got you covered.  

<Steps>
#### Install babel plugin
It's necessary to bundle SQL migration files as string directly to your bundle.
```shell
npm install babel-plugin-inline-import
```

#### Update config files.
You will need to update `babel.config.js`, `metro.config.js` and `drizzle.config.ts` files
```js filename='babel.config.js'
module.exports = function(api) {
  api.cache(true);

  return {
    presets: ['babel-preset-expo'],
    plugins: [["inline-import", { "extensions": [".sql"] }]] // <-- add this
  };
};
```

```js filename="metro.config.js"
const { getDefaultConfig } = require('expo/metro-config');

/** @type {import('expo/metro-config').MetroConfig} */
const config = getDefaultConfig(__dirname);

config.resolver.sourceExts.push('sql'); // <--- add this

module.exports = config;
```

Make sure to have `dialect: 'sqlite'` and `driver: 'expo'` in Drizzle Kit config
```ts filename="drizzle.config.ts"
import { defineConfig } from 'drizzle-kit';

export default defineConfig({
	schema: './db/schema.ts',
	out: './drizzle',
  dialect: 'sqlite',
	driver: 'expo', // <--- very important
});
```

#### Generate migrations
After creating SQL schema file and drizzle.config.ts file, you can generate migrations
```bash
npx drizzle-kit generate
```

#### Add migrations to your app
Now you need to import `migrations.js` file into your Expo/React Native app from `./drizzle` folder. 
You can run migrations on application startup using our custom `useMigrations` migrations hook on in `useEffect` hook manually as you want.

```ts filename="App.tsx"
import { drizzle } from "drizzle-orm/expo-sqlite";
import { openDatabaseSync } from "expo-sqlite";
import { useMigrations } from 'drizzle-orm/expo-sqlite/migrator';
import migrations from './drizzle/migrations';

const expoDb = openDatabaseSync("db.db");

const db = drizzle(expoDb);

export default function App() {
  const { success, error } = useMigrations(db, migrations);

  if (error) {
    return (
      <View>
        <Text>Migration error: {error.message}</Text>
      </View>
    );
  }

  if (!success) {
    return (
      <View>
        <Text>Migration is in progress...</Text>
      </View>
    );
  }

  return ...your application component;
}
```
</Steps>


Source: https://orm.drizzle.team/docs/sqlite/connect-node-sqlite

import Npm from "@mdx/Npm.astro";
import Callout from '@mdx/Callout.astro';
import AnchorCards from '@mdx/AnchorCards.astro';
import Steps from '@mdx/Steps.astro';
import WhatsNextSQLite from "@mdx/WhatsNextSQLite.astro";
import Prerequisites from "@mdx/Prerequisites.astro";
import CodeTabs from "@mdx/CodeTabs.astro";

# Drizzle \<\> Node SQLite

<Prerequisites>
- Database [connection basics](/docs/sqlite/connect-overview) with Drizzle
- Node - [website](https://nodejs.org/)
- Node SQLite driver - [docs](https://nodejs.org/api/sqlite.html)
</Prerequisites>

Drizzle ORM natively supports **[`node:sqlite`](https://nodejs.org/api/sqlite.html)** module

We embrace SQL dialects and dialect specific drivers and syntax and unlike any other ORM, 
for synchronous drivers like `node:sqlite` we have both **async** and **sync** APIs and we mirror most popular 
SQLite-like `all`, `get`, `values` and `run` query methods syntax.

#### Step 1 - Install packages
<Npm>
 drizzle-orm@rc
 -D drizzle-kit@rc
</Npm>

#### Step 2 - Initialize the driver and make a query
```typescript copy
import { drizzle } from 'drizzle-orm/node-sqlite';

const db = drizzle("sqlite.db");

const result = await db.select().from(...);
```

If you need to provide your existing driver:
```typescript copy
import { drizzle } from 'drizzle-orm/node-sqlite';
import { DatabaseSync } from 'node:sqlite';

const sqlite = new DatabaseSync('sqlite.db');
const db = drizzle({ client: sqlite });

const result = await db.select().from(...);
```

If you want to use **sync** APIs:
```typescript copy
import { drizzle } from 'drizzle-orm/node-sqlite';
import { DatabaseSync } from 'node:sqlite';

const sqlite = new DatabaseSync('sqlite.db');
const db = drizzle({ client: sqlite });

const result = db.select().from(users).all();
const result = db.select().from(users).get();
const result = db.select().from(users).values();
const result = db.select().from(users).run();
```

#### What's next?

<WhatsNextSQLite/>


Source: https://orm.drizzle.team/docs/sqlite/connect-op-sqlite

import Npm from "@mdx/Npm.astro";
import Callout from '@mdx/Callout.astro';
import AnchorCards from '@mdx/AnchorCards.astro';
import Steps from '@mdx/Steps.astro';

# Drizzle \<\> OP SQLite
According to the **[official github page](https://github.com/OP-Engineering/op-sqlite)**, 
OP-SQLite embeds the latest version of SQLite and provides a low-level API to execute SQL queries.

<Npm>
 drizzle-orm@rc @op-engineering/op-sqlite
 -D drizzle-kit@rc
</Npm>

```ts
import { drizzle } from "drizzle-orm/op-sqlite";
import { open } from '@op-engineering/op-sqlite';

const opsqlite = open({
  name: 'myDB',
});
const db = drizzle(opsqlite);

await db.select().from(users);
```

You can use Drizzle Kit for SQL migration generation.  
Please make sure to check how [Drizzle Kit migrations](/docs/sqlite/kit-overview) work before proceeding.  
OP SQLite requires you to have SQL migrations bundled into the app and we've got you covered.  

<Steps>

#### Install babel plugin
It's necessary to bundle SQL migration files as string directly to your bundle.
```shell
npm install babel-plugin-inline-import
```

#### Update config files.
You will need to update `babel.config.js`, `metro.config.js` and `drizzle.config.ts` files
```js filename='babel.config.js'
module.exports = {
  presets: ['module:@react-native/babel-preset'],
  plugins: [
    [
      'inline-import',
      {
        extensions: ['.sql'],
      },
    ],
  ],
};
```

```js filename="metro.config.js"
const { getDefaultConfig } = require('@react-native/metro-config');

const config = getDefaultConfig(__dirname);

config.resolver.sourceExts.push('sql');

module.exports = config;
```

Make sure to have `dialect: 'sqlite'` and `driver: 'expo'` in Drizzle Kit config
```ts filename="drizzle.config.ts"
import { defineConfig } from 'drizzle-kit';

export default defineConfig({
	schema: './db/schema.ts',
	out: './drizzle',
  dialect: 'sqlite',
	driver: 'expo', // <--- very important
});
```

#### Generate migrations
After creating SQL schema file and drizzle.config.ts file, you can generate migrations
```bash
npx drizzle-kit generate
```

#### Add migrations to your app
Now you need to import `migrations.js` file into your Expo/React Native app from `./drizzle` folder. 
You can run migrations on application startup using our custom `useMigrations` migrations hook on in `useEffect` hook manually as you want.

```ts filename="App.tsx"
import { drizzle } from "drizzle-orm/op-sqlite";
import { open } from '@op-engineering/op-sqlite';
import { useMigrations } from 'drizzle-orm/op-sqlite/migrator';
import migrations from './drizzle/migrations';

const opsqliteDb = open({
  name: 'myDB',
});

const db = drizzle(opsqliteDb);

export default function App() {
  const { success, error } = useMigrations(db, migrations);

  if (error) {
    return (
      <View>
        <Text>Migration error: {error.message}</Text>
      </View>
    );
  }

  if (!success) {
    return (
      <View>
        <Text>Migration is in progress...</Text>
      </View>
    );
  }

  return ...your application component;
}
```

</Steps>


Source: https://orm.drizzle.team/docs/sqlite/connect-overview

# Database connection with Drizzle

Use these SQLite, libSQL, and on-device SQLite drivers with Drizzle ORM.

## SQLite connection docs

- [SQLite](/docs/sqlite/get-started-sqlite)
- [Turso Cloud](/docs/sqlite/connect-turso)
- [Turso Database](/docs/sqlite/connect-turso-database)
- [SQLite Cloud](/docs/sqlite/connect-sqlite-cloud)
- [Cloudflare D1](/docs/sqlite/connect-cloudflare-d1)
- [Bun SQLite](/docs/sqlite/connect-bun-sqlite)
- [Node SQLite](/docs/sqlite/connect-node-sqlite)
- [Cloudflare Durable Objects](/docs/sqlite/connect-cloudflare-do)
- [Expo SQLite](/docs/sqlite/connect-expo-sqlite)
- [OP SQLite](/docs/sqlite/connect-op-sqlite)
- [React Native SQLite](/docs/sqlite/connect-react-native-sqlite)
- [Drizzle HTTP proxy](/docs/sqlite/connect-drizzle-proxy)


Source: https://orm.drizzle.team/docs/sqlite/connect-react-native-sqlite

import Npm from "@mdx/Npm.astro";
import Callout from '@mdx/Callout.astro';
import AnchorCards from '@mdx/AnchorCards.astro';
import Steps from '@mdx/Steps.astro';

# Drizzle \<\> React Native SQLite
Please use [`Expo SQLite`](#expo-sqlite) to run Drizzle ORM with React Native apps.  
The only [popular library](https://github.com/andpor/react-native-sqlite-storage) we've found does not support new Hermes JavaScript runtime, 
which is a standard out of the box runtime for React Native and Expo now.



Source: https://orm.drizzle.team/docs/sqlite/connect-sqlite-cloud

import Tab from '@mdx/Tab.astro';
import Tabs from '@mdx/Tabs.astro';
import Npm from "@mdx/Npm.astro";
import Callout from '@mdx/Callout.astro';
import Steps from '@mdx/Steps.astro';
import AnchorCards from '@mdx/AnchorCards.astro';
import Prerequisites from "@mdx/Prerequisites.astro";
import CodeTabs from "@mdx/CodeTabs.astro";
import Section from "@mdx/Section.astro";
import WhatsNextSQLite from "@mdx/WhatsNextSQLite.astro";

# Drizzle \<\> SQLite Cloud
<Prerequisites>
- Database [connection basics](/docs/sqlite/connect-overview) with Drizzle
- **SQLite Cloud database** - [docs](https://docs.sqlitecloud.io/docs/overview)
- **SQLite Cloud driver** - [docs](https://docs.sqlitecloud.io/docs/sdk-js-introduction) & [GitHub](https://github.com/sqlitecloud/sqlitecloud-js)
</Prerequisites>

According to the **[official website](https://docs.sqlitecloud.io/docs/overview)**, SQLite Clouds is a managed, distributed relational database system built on top of the SQLite database engine. 

#### Step 1 - Install packages
<Npm>
 drizzle-orm@rc @sqlitecloud/drivers
 -D drizzle-kit@rc
</Npm>

#### Step 2 - Initialize the driver and make a query
```typescript
import { drizzle } from 'drizzle-orm/sqlite-cloud';

const db = drizzle(process.env.SQLITE_CLOUD_CONNECTION_STRING);

const result = await db.all('select 1');
```

If you need to provide your existing drivers:

```typescript
import { Database } from '@sqlitecloud/drivers';
import { drizzle } from 'drizzle-orm/sqlite-cloud';

const client = new Database(process.env.SQLITE_CLOUD_CONNECTION_STRING!);
const db = drizzle({ client });

const result = await db.all('select 1');
```

#### What's next?

<WhatsNextSQLite/>


Source: https://orm.drizzle.team/docs/sqlite/connect-turso-database

import Npm from "@mdx/Npm.astro";
import Callout from '@mdx/Callout.astro';
import AnchorCards from '@mdx/AnchorCards.astro';
import Steps from '@mdx/Steps.astro';
import WhatsNextSQLite from "@mdx/WhatsNextSQLite.astro";
import Prerequisites from "@mdx/Prerequisites.astro";
import CodeTabs from "@mdx/CodeTabs.astro";
import LibsqlTable from "@mdx/LibsqlTable.mdx";
import LibsqlTabs from "@mdx/LibsqlTabs.mdx";

# Drizzle \<\> Turso Database

<Prerequisites>
- Database [connection basics](/docs/sqlite/connect-overview) with Drizzle
- Turso Database - [website](https://docs.turso.tech/introduction)
- Turso Database driver - [website](https://docs.turso.tech/connect/javascript) & [GitHub](https://github.com/tursodatabase/turso/tree/main/bindings/javascript)
</Prerequisites>

According to the **[official website](https://docs.turso.tech/introduction)**, 
Turso is the small database to power your big dreams in the age of AI.

#### Step 1 - Install packages
<Npm>
 drizzle-orm@rc @tursodatabase/database
 -D drizzle-kit@rc
</Npm>

#### Step 2 - Initialize the driver and make a query
```typescript
import { drizzle } from 'drizzle-orm/tursodatabase/database';

const db = drizzle('sqlite.db');

const result = await db.all('select 1');
```

If you need to provide your existing drivers:

```typescript
import { Database } from '@tursodatabase/database';
import { drizzle } from 'drizzle-orm/tursodatabase/database';

const client = new Database('sqlite.db');
const db = drizzle({ client });

const result = await db.all('select 1');
```

#### What's next?

<WhatsNextSQLite/>


Source: https://orm.drizzle.team/docs/sqlite/connect-turso-serverless

import Npm from "@mdx/Npm.astro";
import Callout from '@mdx/Callout.astro';
import AnchorCards from '@mdx/AnchorCards.astro';
import Steps from '@mdx/Steps.astro';
import WhatsNextSQLite from "@mdx/WhatsNextSQLite.astro";
import Prerequisites from "@mdx/Prerequisites.astro";
import CodeTabs from "@mdx/CodeTabs.astro";
import LibsqlTable from "@mdx/LibsqlTable.mdx";
import LibsqlTabs from "@mdx/LibsqlTabs.mdx";

# Drizzle \<\> Turso Database Serverless

<Prerequisites>
- Database [connection basics](/docs/sqlite/connect-overview) with Drizzle
- Turso Database - [website](https://docs.turso.tech/introduction)
- Turso Database serverless driver - [website](https://docs.turso.tech/sdk/ts/quickstart#recommended-@tursodatabase/serverless-remote-/-over-the-wire) & [GitHub](https://github.com/tursodatabase/turso/tree/main/serverless/javascript)
</Prerequisites>

According to the **[official website](https://docs.turso.tech/introduction)**, 
Turso is the small database to power your big dreams in the age of AI.

#### Step 1 - Install packages
<Npm>
 drizzle-orm@rc @tursodatabase/serverless
 -D drizzle-kit@rc
</Npm>

#### Step 2 - Initialize the driver and make a query
```typescript
import { drizzle } from 'drizzle-orm/tursodatabase-serverless';

const db = drizzle({
	connection: {
		url: process.env.TURSO_URL,
		authToken: process.env.TURSO_TOKEN
	}
});

const result = await db.all('select 1');
```

If you need to provide your existing drivers:

```typescript
import { connect } from '@tursodatabase/serverless';
import { drizzle } from 'drizzle-orm/tursodatabase-serverless';

const client = connect({
    url: process.env.TURSO_URL,
    authToken: process.env.TURSO_TOKEN
});
const db = drizzle({ client });

const result = await db.all('select 1');
```

#### What's next?

<WhatsNextSQLite/>


Source: https://orm.drizzle.team/docs/sqlite/connect-turso-sync

import Npm from "@mdx/Npm.astro";
import Callout from '@mdx/Callout.astro';
import AnchorCards from '@mdx/AnchorCards.astro';
import Steps from '@mdx/Steps.astro';
import WhatsNextSQLite from "@mdx/WhatsNextSQLite.astro";
import Prerequisites from "@mdx/Prerequisites.astro";
import CodeTabs from "@mdx/CodeTabs.astro";
import LibsqlTable from "@mdx/LibsqlTable.mdx";
import LibsqlTabs from "@mdx/LibsqlTabs.mdx";

# Drizzle \<\> Turso Database Sync

<Prerequisites>
- Database [connection basics](/docs/sqlite/connect-overview) with Drizzle
- Turso Database - [website](https://docs.turso.tech/introduction)
- Turso Database sync driver - [GitHub](https://github.com/tursodatabase/turso/tree/main/bindings/javascript/sync)
</Prerequisites>

According to the **[official website](https://docs.turso.tech/introduction)**, 
Turso is the small database to power your big dreams in the age of AI.

#### Step 1 - Install packages
<Npm>
 drizzle-orm@rc @tursodatabase/sync
 -D drizzle-kit@rc
</Npm>

#### Step 2 - Initialize the driver and make a query
```typescript
import { drizzle } from 'drizzle-orm/tursodatabase-sync';

const db = drizzle({
	connection: {
    	path: 'local.db',                // path used as a prefix for local files created by sync-engine
    	url: 'https://<db>.turso.io',    // URL of the remote database: turso db show <db>
    	authToken: '...',                // auth token issued from the Turso Cloud: turso db tokens create <db>
    	clientName: 'turso-sync-example' // arbitrary client name
	}
});

const result = await db.all('select 1');
```

If you need to provide your existing drivers:

```typescript
import { connect } from '@tursodatabase/sync';
import { drizzle } from 'drizzle-orm/tursodatabase-sync';

const client = await connect({
    path: 'local.db',                // path used as a prefix for local files created by sync-engine
    url: 'https://<db>.turso.io',    // URL of the remote database: turso db show <db>
    authToken: '...',                // auth token issued from the Turso Cloud: turso db tokens create <db>
    clientName: 'turso-sync-example' // arbitrary client name
});
const db = drizzle({ client });

const result = await db.all('select 1');
```

#### What's next?

<WhatsNextSQLite/>


Source: https://orm.drizzle.team/docs/sqlite/connect-turso

import Npm from "@mdx/Npm.astro";
import Callout from '@mdx/Callout.astro';
import AnchorCards from '@mdx/AnchorCards.astro';
import Steps from '@mdx/Steps.astro';
import WhatsNextSQLite from "@mdx/WhatsNextSQLite.astro";
import Prerequisites from "@mdx/Prerequisites.astro";
import CodeTabs from "@mdx/CodeTabs.astro";
import LibsqlTable from "@mdx/LibsqlTable.mdx";
import LibsqlTabs from "@mdx/LibsqlTabs.mdx";

# Drizzle \<\> Turso Cloud

<Prerequisites>
- Database [connection basics](/docs/sqlite/connect-overview) with Drizzle
- Turso Cloud - [website](https://docs.turso.tech/turso-cloud)
- Turso Cloud driver - [website](https://docs.turso.tech/sdk/ts/reference) & [GitHub](https://github.com/tursodatabase/libsql-client-ts)
</Prerequisites>

According to the **[official website](https://turso.tech/drizzle)**, 
Turso is a **[libSQL](https://github.com/libsql/libsql)** powered edge SQLite database as a service.
  
Drizzle ORM natively supports libSQL driver.
We embrace SQL dialects and dialect specific drivers and syntax and mirror most popular 
SQLite-like `all`, `get`, `values` and `run` query methods syntax. 

#### Step 1 - Install packages
<Npm>
 drizzle-orm@rc @libsql/client
 -D drizzle-kit@rc
</Npm>

#### Step 2 - Initialize the driver
Drizzle has native support for all `@libsql/client` driver variations:

<LibsqlTable />

<br />

<LibsqlTabs />


If you need to provide your existing driver:

<CodeTabs items={["default", "web"]}>
```typescript copy
import { drizzle } from 'drizzle-orm/libsql';
import { createClient } from '@libsql/client';

const client = createClient({ 
  url: process.env.DATABASE_URL,
  authToken: process.env.DATABASE_AUTH_TOKEN
});

const db = drizzle({ client });

const result = await db.select().from(users).all()
```
```typescript copy
import { drizzle } from 'drizzle-orm/libsql/web';
import { createClient } from '@libsql/client/web';

const client = createClient({ 
  url: process.env.DATABASE_URL,
  authToken: process.env.DATABASE_AUTH_TOKEN
});

const db = drizzle({ client });

const result = await db.select().from(users).all()
```
</CodeTabs>

#### Step 3 - make a query

```ts
import { drizzle } from 'drizzle-orm/libsql';
import * as s from 'drizzle-orm/sqlite-core';

const db = drizzle({ connection: {
  url: process.env.DATABASE_URL, 
  authToken: process.env.DATABASE_AUTH_TOKEN 
}});

const users = s.sqliteTable("users", {
  id: s.integer(),
  name: s.text(),
})

const result = await db.select().from(users);
```

#### What's next?

<WhatsNextSQLite/>


Source: https://orm.drizzle.team/docs/sqlite/custom-types

# Custom types

Custom types let you define your own column types with custom SQL data types and JS/DB value transforms

SQLite exposes `customType` from `drizzle-orm/sqlite-core`.

## Examples
The best way to see how `customType` definition is working is to check how data types could be defined using `customType` function from Drizzle ORM.

#### Int

```ts
import { customType, sqliteTable } from 'drizzle-orm/sqlite-core';

const customInt = customType<{ data: number }>({
  dataType() {
    return 'int';
  },
});

export const users = sqliteTable('users', {
  id: customInt(),
});

```

#### Text
```ts
import { customType, sqliteTable } from 'drizzle-orm/sqlite-core';

const customText = customType<{ data: string }>({
  dataType() {
    return 'text';
  },
});

export const users = sqliteTable('users', {
  name: customText(),
});
```

#### Hex
```ts
import { customType, sqliteTable } from 'drizzle-orm/sqlite-core';

const customHex = customType<{
  data: string;
  driverData: string;
  config: { mode: 'text' | 'blob' };
  configRequired: false;
}>({
  dataType(config) {
    return config?.mode ? config.mode : 'text';
  },
  fromDriver(value: string): string {
    return value.startsWith('0x') ? value : `0x${value}`;
  },
  toDriver(value: string): string {
    return value.replace(/^0x/, '');
  },
});

export const users = sqliteTable('users', {
  wallet: customHex('wallet', { mode: 'text' }),
});
```

Usage for all types will be same as defined functions in Drizzle ORM. For example:
```ts
const usersTable = mysqlTable("users", {
  id: customInt().primaryKey(),
  name: customText().notNull(),
  wallet: customHex('wallet', { mode: 'text' })
});
```

### TS-doc for type definitions

You can check `ts-doc` for types, param definition and examples

```ts
export interface CustomTypeValues {
	/**
	 * Required type for custom column, that will infer proper type model
	 *
	 * Examples:
	 *
	 * If you want your column to be `string` type after selecting/or on inserting - use `data: string`. Like `text`, `varchar`
	 *
	 * If you want your column to be `number` type after selecting/or on inserting - use `data: number`. Like `integer`
	 */
	data: unknown;

	/**
	 * Type helper, that represents what type database driver is accepting for specific database data type
	 */
	driverData?: unknown;

	/**
	 * Type helper, that represents what type database driver is returning for specific database data type
	 *
	 * Needed only in case driver's output and input for type differ
	 *
	 * Defaults to {@link driverData}
	 */
	driverOutput?: unknown;

	/**
	 * Type helper, that represents what type field returns after being aggregated to JSON
	 */
	jsonData?: unknown;

	/**
	 * What config type should be used for {@link CustomTypeParams} `dataType` generation
	 */
	config?: Record<string, any>;

	/**
	 * Whether the config argument should be required or not
	 * @default false
	 */
	configRequired?: boolean;

	/**
	 * If your custom data type should be notNull by default you can use `notNull: true`
	 *
	 * @example
	 * const customSerial = customType<{ data: number, notNull: true, default: true }>({
	 * 	  dataType() {
	 * 	    return 'serial';
	 *    },
	 * });
	 */
	notNull?: boolean;

	/**
	 * If your custom data type has default you can use `default: true`
	 *
	 * @example
	 * const customSerial = customType<{ data: number, notNull: true, default: true }>({
	 * 	  dataType() {
	 * 	    return 'serial';
	 *    },
	 * });
	 */
	default?: boolean;
}

export interface CustomTypeParams<T extends CustomTypeValues> {
	/**
	 * Database data type string representation, that is used for migrations
	 * @example
	 * ```
	 * `jsonb`, `text`
	 * ```
	 *
	 * If database data type needs additional params you can use them from `config` param
	 * @example
	 * ```
	 * `varchar(256)`, `numeric(2,3)`
	 * ```
	 *
	 * To make `config` be of specific type please use config generic in {@link CustomTypeValues}
	 *
	 * @example
	 * Usage example
	 * ```
	 *   dataType() {
	 *     return 'boolean';
	 *   },
	 * ```
	 * Or
	 * ```
	 *   dataType(config) {
	 * 	   return typeof config.length !== 'undefined' ? `varchar(${config.length})` : `varchar`;
	 * 	 }
	 * ```
	 */
	dataType: (config: T['config'] | (Equal<T['configRequired'], true> extends true ? never : undefined)) => string;

	/**
	 * Optional mapping function, that is used to transform inputs from desired to be used in code format to one suitable for driver
	 * @example
	 * For example, when using jsonb we need to map JS/TS object to string before writing to database
	 * ```
	 * toDriver(value: TData): string {
	 * 	 return JSON.stringify(value);
	 * }
	 * ```
	 */
	toDriver?: (value: T['data']) => T['driverData'] | SQL;

	/**
	 * Optional mapping function, that is used for transforming data returned by driver to desired column's output format
	 * @example
	 * For example, when using timestamp we need to map string Date representation to JS Date
	 * ```
	 * fromDriver(value: string): Date {
	 * 	return new Date(value);
	 * }
	 * ```
	 *
	 * It'll cause the returned data to change from:
	 * ```
	 * {
	 * 	customField: "2025-04-07T03:25:16.635Z";
	 * }
	 * ```
	 * to:
	 * ```
	 * {
	 * 	customField: new Date("2025-04-07T03:25:16.635Z");
	 * }
	 * ```
	 */
	fromDriver?: (value: 'driverOutput' extends keyof T ? T['driverOutput'] : T['driverData']) => T['data'];

	/**
	 * Optional mapping function, that is used for transforming data returned by transofmed to JSON in database data to desired format
	 *
	 * Used by [relational queries](https://orm.drizzle.team/docs/rqb)
	 *
	 * Defaults to {@link fromDriver} function
	 * @example
	 * For example, when querying blob column via [RQB](https://orm.drizzle.team/docs/rqb) or [JSON functions](https://orm.drizzle.team/docs/json-functions), the result field will be returned as it's hex string representation, as opposed to Buffer from regular query
	 * To handle that, we need a separate function to handle such field's mapping:
	 * ```
	 * fromJson(value: string): Buffer {
	 * 	return Buffer.from(value, 'hex');
	 * },
	 * ```
	 *
	 * It'll cause the returned data to change from:
	 * ```
	 * {
	 * 	customField: "04A8...";
	 * }
	 * ```
	 * to:
	 * ```
	 * {
	 * 	customField: Buffer([...]);
	 * }
	 * ```
	 */
	fromJson?: (value: T['jsonData']) => T['data'];

	/**
	 * Optional selection modifier function, that is used for modifying selection of column inside [JSON functions](https://orm.drizzle.team/docs/json-functions)
	 *
	 * Additional mapping that could be required for such scenarios can be handled using {@link fromJson} function
	 *
	 * Used by [relational queries](https://orm.drizzle.team/docs/rqb)
	 *
	 * Following types are being casted to text by default: `numeric`, `decimal`, `bigint`, `blob` (via `hex()` function)
	 * @example
	 * For example, when using numeric field for bigint storage we need to cast field to text to preserve data integrity
	 * ```
	 * forJsonSelect(identifier: SQL, sql: SQLGenerator): SQL {
	 * 	return sql`cast(${identifier} as text)`
	 * },
	 * ```
	 *
	 * This will change query from:
	 * ```
	 * SELECT
	 * 	json_object('bigint', `t`.`bigint`)
	 * 	FROM
	 * 	(
	 * 		SELECT
	 * 		`table`.`custom_bigint` AS "bigint"
	 * 		FROM
	 * 		`table`
	 * 	) AS `t`
	 * ```
	 * to:
	 * ```
	 * SELECT
	 * 	json_object('bigint', `t`.`bigint`)
	 * 	FROM
	 * 	(
	 * 		SELECT
	 * 		cast(`table`.`custom_bigint` as text) AS `bigint`
	 * 		FROM
	 * 		`table`
	 * 	) AS `t`
	 * ```
	 *
	 * Returned by query object will change from:
	 * ```
	 * {
	 * 	bigint: 5044565289845416000; // Partial data loss due to direct conversion to JSON format
	 * }
	 * ```
	 * to:
	 * ```
	 * {
	 * 	bigint: "5044565289845416380"; // Data is preserved due to conversion of field to text before JSON-ification
	 * }
	 * ```
	 */
	forJsonSelect?: (identifier: SQL, sql: SQLGenerator) => SQL;
}
```

Source: https://orm.drizzle.team/docs/sqlite/data-querying

import Callout from '@mdx/Callout.astro';
import CodeTabs from "@mdx/CodeTabs.astro";
import Section from '@mdx/Section.astro';
import Flex from "@mdx/Flex.astro"
import LinksList from "@mdx/LinksList.astro"
import Prerequisites from "@mdx/Prerequisites.astro";

# Drizzle Queries + CRUD

<Prerequisites>
  - How to define your schema - [Schema Fundamentals](/docs/sqlite/sql-schema-declaration)
  - How to connect to the database - [Connection Fundamentals](/docs/sqlite/connect-overview)
</Prerequisites>

Drizzle gives you a few ways for querying your database and it's up to you to decide which one you'll need in your next project.
It can be either SQL-like syntax or Relational Syntax. Let's check them:

## Why SQL-like?
\
**If you know SQL, you know Drizzle.**

Other ORMs and data frameworks tend to deviate from or abstract away SQL, leading to a double learning curve: you need to learn both SQL and the framework's API.

Drizzle is the opposite.
We embrace SQL and built Drizzle to be SQL-like at its core, so you have little to no learning curve and full access to the power of SQL.

<Section>
```typescript copy
// Access your data
await db
  .select()
	.from(posts)
	.leftJoin(comments, eq(posts.id, comments.post_id))
	.where(eq(posts.id, 10))
```
```sql
SELECT * 
FROM posts
LEFT JOIN comments ON posts.id = comments.post_id
WHERE posts.id = 10
```
</Section>

With SQL-like syntax, you can replicate much of what you can do with pure SQL and know 
exactly what Drizzle will do and what query will be generated. You can perform a wide range of queries, 
including select, insert, update, delete, as well as using aliases, WITH clauses, subqueries, prepared statements, 
and more. Let's look at more examples

<CodeTabs items={['insert', 'update', 'delete']}>
<Section>
```ts
await db.insert(users).values({ email: 'user@gmail.com' })
```
```sql
INSERT INTO users (email) VALUES ('user@gmail.com')
```
</Section>
<Section>
```ts
await db.update(users)
        .set({ email: 'user@gmail.com' })
        .where(eq(users.id, 1))
```
```sql
UPDATE users 
SET email = 'user@gmail.com'
WHERE users.id = 1
```
</Section>
<Section>
```ts
await db.delete(users).where(eq(users.id, 1))
```
```sql
DELETE FROM users WHERE users.id = 1
```
</Section>
</CodeTabs>

## Why not SQL-like?

We're always striving for a perfectly balanced solution. While SQL-like queries cover 100% of your needs, 
there are certain common scenarios where data can be queried more efficiently.

We've built the Queries API so you can fetch relational, nested data from the database in the most convenient 
and performant way, without worrying about joins or data mapping.

**Drizzle always outputs exactly one SQL query**. Feel free to use it with serverless databases,
and never worry about performance or roundtrip costs!

<Section>
```ts
const result = await db.query.users.findMany({
	with: {
		posts: true
	},
});
```
{/* ```sql
SELECT * FROM users ...
``` */}
</Section>

## Advanced
With Drizzle, queries can be composed and partitioned in any way you want. You can compose filters 
independently from the main query, separate subqueries or conditional statements, and much more. 
Let's check a few advanced examples:

#### Compose a WHERE statement and then use it in a query
```ts
async function getProductsBy({
  name,
  category,
  maxPrice,
}: {
  name?: string;
  category?: string;
  maxPrice?: number;
}) {
  const filters: SQL[] = [];

  if (name) filters.push(like(products.name, name));
  if (category) filters.push(eq(products.category, category));
  if (maxPrice) filters.push(lte(products.price, maxPrice));

  return db
    .select()
    .from(products)
    .where(and(...filters));
}
```

#### Separate subqueries into different variables, and then use them in the main query
```ts
const subquery = db
	.select()
	.from(internalStaff)
	.leftJoin(customUser, eq(internalStaff.userId, customUser.id))
	.as('internal_staff');

const mainQuery = await db
	.select()
	.from(ticket)
	.leftJoin(subquery, eq(subquery.internal_staff.userId, ticket.staffId));
```

#### What's next?
<br/>
<Flex>
  <LinksList 
    title='Access your data'
    links={[
        ["Query", "/docs/sqlite/rqb"], 
        ["Select", "/docs/sqlite/select"],
        ["Insert", "/docs/sqlite/insert"],
        ["Update", "/docs/sqlite/update"],
        ["Delete", "/docs/sqlite/delete"],
        ["Filters", "/docs/sqlite/operators"],
        ["Joins", "/docs/sqlite/joins"],
        ["sql`` operator", "/docs/sqlite/sql"],
      ]}
  />
  <LinksList 
    title='Zero to Hero'
    links={[
        ["Migrations", "/docs/sqlite/migrations"], 
      ]}
  />
</Flex>


Source: https://orm.drizzle.team/docs/sqlite/delete

import Callout from '@mdx/Callout.astro';
import Section from '@mdx/Section.astro';

# SQL Delete
You can delete all rows in the table:
```typescript copy
await db.delete(users);
```
And you can delete with filters and conditions:
```typescript copy
await db.delete(users).where(eq(users.name, 'Dan'));
```

### Limit
Use `.limit()` to add `limit` clause to the query - for example:
<Section>
```typescript
await db.delete(users).where(eq(users.name, 'Dan')).limit(2);
```
```sql
delete from "users" where "users"."name" = ? limit ?;
```
</Section>

### Order By
Use `.orderBy()` to add `order by` clause to the query, sorting the results by the specified fields:
<Section>
```typescript
import { asc, desc } from 'drizzle-orm';

await db.delete(users).where(eq(users.name, 'Dan')).orderBy(users.name);
await db.delete(users).where(eq(users.name, 'Dan')).orderBy(desc(users.name));

// order by multiple fields
await db.delete(users).where(eq(users.name, 'Dan')).orderBy(users.name, users.name2);
await db.delete(users).where(eq(users.name, 'Dan')).orderBy(asc(users.name), desc(users.name2));
```
```sql
delete from "users" where "users"."name" = ? order by "name";
delete from "users" where "users"."name" = ? order by "name" desc;

delete from "users" where "users"."name" = ? order by "name", "name2";
delete from "users" where "users"."name" = ? order by "name" asc, "name2" desc;
```
</Section>

### Returning
You can delete a row and get it back in SQLite:
```typescript copy
const deletedUser = await db.delete(users)
  .where(eq(users.name, 'Dan'))
  .returning();

// partial return
const deletedUserIds: { deletedId: number }[] = await db.delete(users)
  .where(eq(users.name, 'Dan'))
  .returning({ deletedId: users.id });
```

## WITH DELETE clause

<Callout>
  Check how to use WITH statement with [select](/docs/sqlite/select#with-clause), [insert](/docs/sqlite/insert#with-insert-clause), [update](/docs/sqlite/update#with-update-clause)
</Callout>

Using the `with` clause can help you simplify complex queries by splitting them into smaller subqueries called common table expressions (CTEs):
<Section>
```typescript copy
const averageAmount = db.$with('average_amount').as(
  db.select({ value: sql`avg(${orders.amount})`.as('value') }).from(orders)
);

const result = await db
	.with(averageAmount)
	.delete(orders)
	.where(gt(orders.amount, sql`(select * from ${averageAmount})`))
	.returning({
		id: orders.id
	});
```
```sql
with "average_amount" as (select avg("amount") as "value" from "orders") 
delete from "orders" 
where "orders"."amount" > (select * from "average_amount") 
returning "id"
```
</Section>


Source: https://orm.drizzle.team/docs/sqlite/drizzle-config-file

import CodeTab from "@mdx/CodeTab.astro";
import CodeTabs from "@mdx/CodeTabs.astro";
import Section from "@mdx/Section.astro";
import Tab from "@mdx/Tab.astro";
import Tabs from "@mdx/Tabs.astro";
import Callout from "@mdx/Callout.astro";
import SchemaFilePaths from "@mdx/SchemaFilePaths.mdx"
import Prerequisites from "@mdx/Prerequisites.astro"
import Dialects from "@mdx/Dialects.mdx"
import Drivers from "@mdx/Drivers.mdx"
import DriversExamples from "@mdx/DriversExamples.mdx"
import Npx from "@mdx/Npx.astro"

# Drizzle Kit configuration file
<Prerequisites>
- Get started with Drizzle and `drizzle-kit` - [read here](/docs/sqlite/get-started)
- Drizzle schema fundamentals - [read here](/docs/sqlite/sql-schema-declaration)
- Database connection basics - [read here](/docs/sqlite/connect-overview)
- Drizzle migrations fundamentals - [read here](/docs/sqlite/migrations)
- Drizzle Kit [overview](/docs/sqlite/kit-overview) and [config file](/docs/sqlite/drizzle-config-file)
</Prerequisites>

Drizzle Kit lets you declare configuration options in `TypeScript` or `JavaScript` configuration files.

<Section>
```plaintext {5}
📦 <project root>
 ├ ...
 ├ 📂 drizzle
 ├ 📂 src
 ├ 📜 drizzle.config.ts
 └ 📜 package.json
```
<CodeTabs items={["drizzle.config.ts", "drizzle.config.js"]}>
<CodeTab>
```ts
import { defineConfig } from "drizzle-kit";

export default defineConfig({
  dialect: "sqlite",
  schema: "./src/schema.ts",
  out: "./drizzle",
});
```
</CodeTab>
<CodeTab>
```js
import { defineConfig } from "drizzle-kit";

export default defineConfig({
  dialect: "sqlite",
  schema: "./src/schema.ts",
  out: "./drizzle",
});
```
</CodeTab>
</CodeTabs>
</Section>

Example of an extended config file
```ts collapsable
import { defineConfig } from "drizzle-kit";

export default defineConfig({
  out: "./drizzle",
  dialect: "sqlite",
  schema: "./src/schema.ts",

  driver: "d1-http",
  dbCredentials: {
    url: "./sqlite.db",
  },

  tablesFilter: "*",

  introspect: {
    casing: "camel",
  },

  migrations: {
    table: "__drizzle_migrations__",
  },

  breakpoints: true,
  verbose: true,
});
```

### Multiple configuration files
You can have multiple config files in the project, it's very useful when you have multiple database stages or multiple databases or different databases on the same project:
<Npx>
  drizzle-kit generate --config=drizzle-dev.config.ts
  drizzle-kit generate --config=drizzle-prod.config.ts
</Npx>
```plaintext {5-6}
📦 <project root>
 ├ 📂 drizzle
 ├ 📂 src
 ├ 📜 .env
 ├ 📜 drizzle-dev.config.ts
 ├ 📜 drizzle-prod.config.ts
 ├ 📜 package.json
 └ 📜 tsconfig.json
```

### Migrations folder
`out` param lets you define folder for your migrations, it's optional and `drizzle` by default.  
It's very useful since you can have many separate schemas for different databases in the same project 
and have different migration folders for them.  
  
Migration folder contains folders with `.sql` migration files which is used by `drizzle-kit`

<Section>
```plaintext {3}
📦 <project root>
 ├ ...
 ├ 📂 drizzle
 │ ├ 📂 20242409125510_premium_mister_fear
 │ ├ 📜 user.ts 
 │ ├ 📜 post.ts 
 │ └ 📜 comment.ts 
 ├ 📂 src
 ├ 📜 drizzle.config.ts
 └ 📜 package.json
```
```ts {6}
import { defineConfig } from "drizzle-kit";

export default defineConfig({
  dialect: "sqlite",
  schema: "./src/schema/*",
  out: "./drizzle",
});
```
</Section>

## ---

### `dialect`
<rem025/>

Dialect of the database you're using 
|               |                                                 |
| :------------ | :-----------------------------------            |
| type        | <Dialects/>                                     |
| default        | --                                     |
| commands    | `generate`, `push`, `pull`, `studio`,  `migrate`, `up`, `export` |

<rem025/>
```ts {4}
import { defineConfig } from "drizzle-kit";

export default defineConfig({
  dialect: "sqlite", 
});
```


### `schema`
<rem025/>

[`glob`](https://www.digitalocean.com/community/tools/glob?comments=true&glob=/**/*.js&matches=false&tests=//%20This%20will%20match%20as%20it%20ends%20with%20'.js'&tests=/hello/world.js&tests=//%20This%20won't%20match!&tests=/test/some/globs)
 based path to drizzle schema file(s) or folder(s) contaning schema files.
|               |                      |
| :------------ | :-----------------   |
| type          | `string` `string[]` |
| default        | --                    |
| commands      | `generate`, `push`, `export`, `studio`  |

<rem025/>
<SchemaFilePaths />


### `out`
<rem025/>

Defines output folder of your SQL migration files, json snapshots of your schema and `schema.ts` from `drizzle-kit pull` command.
|               |                      |
| :------------ | :-----------------   |
| type          | `string` `string[]` |
| default        | `drizzle`                    |
| commands      | `generate`, `pull`, `migrate`, `check`, `up` |

<rem025/>
```ts {4}
import { defineConfig } from "drizzle-kit";

export default defineConfig({
  out: "./drizzle", 
});
```

### `driver`
<rem025/>

Drizzle Kit automatically picks an available SQLite driver from your current project based on `dialect: "sqlite"`.
Use `driver` for SQLite driver exceptions, such as Cloudflare D1 HTTP.

|               |                      |
| :------------ | :-----------------   |
| type          | `d1-http` |
| default        | --                    |
| commands      | `push`, `migrate`, `pull`, `studio`  |

<rem025/>

```ts {5}
import { defineConfig } from "drizzle-kit";

export default defineConfig({
  dialect: "sqlite",
  driver: "d1-http",
  dbCredentials: {
    accountId: "accountId",
    databaseId: "databaseId",
    token: "token",
  },
});
```

## ---

### `dbCredentials`
<rem025/>

Database connection credentials in a form of `url`, 
`user:password@host:port/db` params or exceptions drivers(<Drivers/>) specific connection options.

|               |                      |
| :------------ | :-----------------   |
| type          | <Dialects/> |
| default       | --                    |
| commands      | `push`, `pull`, `migrate`, `studio` |

<rem025/>

<CodeTabs items={["SQLite", "Turso", "Cloudflare D1"]}>
```ts
import { defineConfig } from 'drizzle-kit'

export default defineConfig({
  dialect: "sqlite",
  dbCredentials: {
    url: ":memory:", // in-memory database
    // or
    url: "sqlite.db", 
    // or
    url: "file:sqlite.db" // file: prefix is required by libsql
  }
});
```
```ts
import { defineConfig } from 'drizzle-kit'

export default defineConfig({
  dialect: "turso",
  dbCredentials: {
    url: "libsql://acme.turso.io" // remote Turso database url
    authToken: "...",

    // or if you need local db

    url: ":memory:", // inmemory database
    // or
    url: "file:sqlite.db", // file: prefix is required by libsql
  }
});
```
```ts
import { defineConfig } from 'drizzle-kit'

export default defineConfig({
  dialect: "sqlite",
  driver: "d1-http",
  dbCredentials: {
    accountId: "accountId",
    databaseId: "databaseId",
    token: "token",
  },
});
```
</CodeTabs>

### `migrations`
<rem025/>

When running `drizzle-kit migrate` - drizzle will records about 
successfully applied migrations in your database in log table named `__drizzle_migrations`.

`migrations` config options lets you change the migrations log `table` name.

|               |                      |
| :------------ | :-----------------   |
| type          | `{ table: string }` |
| default       | `{ table: "__drizzle_migrations" }`                    |
| commands      | `migrate`, `push`, `pull` |

<rem025/>

```ts
export default defineConfig({
  dialect: "sqlite",
  schema: "./src/schema.ts",
  migrations: {
    table: 'my-migrations-table', // `__drizzle_migrations` by default
  },
});
```

### `introspect`
<rem025/>

Configuration for `drizzle-kit pull` command.

`casing` is responsible for in-code column keys casing

|               |                      |
| :------------ | :-----------------   |
| type          | `{ casing: "preserve" \| "camel" }` |
| default       | `{ casing: "camel" }`                    |
| commands      | `pull`   |

<rem025/>

<CodeTabs items={["camel", "preserve"]}>
<Section>
```ts
import * as p from "drizzle-orm/sqlite-core"

export const users = p.sqliteTable("users", {
  id: p.integer().primaryKey({ autoIncrement: true }),
  firstName: p.text("first-name"),
  lastName: p.text("LastName"),
  email: p.text("email"),
  phoneNumber: p.text("phone_number"),
});
```
```sql
PRAGMA table_info(users);
```
``` 
 column_name   | data_type        
---------------+------------------------
 id            | integer
 first-name    | text
 LastName      | text
 email         | text
 phone_number  | text
```
</Section>
<Section>
```ts
import * as p from "drizzle-orm/sqlite-core"

export const users = p.sqliteTable("users", {
  id: p.integer().primaryKey({ autoIncrement: true }),
  "first-name": p.text("first-name"),
  LastName: p.text("LastName"),
  email: p.text("email"),
  phone_number: p.text("phone_number"),
});
```
```sql
PRAGMA table_info(users);
```
``` 
 column_name   | data_type        
---------------+------------------------
 id            | integer
 first-name    | text
 LastName      | text
 email         | text
 phone_number  | text
```
</Section>
</CodeTabs>


## --- 

### `tablesFilter`
<Callout>
If you want to run multiple projects with one database - check out [our guide](/docs/sqlite/goodies#multi-project-schema).
</Callout>
<rem025/>
`drizzle-kit push` and `drizzle-kit pull` will manage all tables by default.
You can configure the list of tables via `tablesFilter`.

`tablesFilter` option lets you specify [`glob`](https://www.digitalocean.com/community/tools/glob?comments=true&glob=/**/*.js&matches=false&tests=//%20This%20will%20match%20as%20it%20ends%20with%20'.js'&tests=/hello/world.js&tests=//%20This%20won't%20match!&tests=/test/some/globs) 
based table names filter, e.g. `["users", "user_info"]` or `"user*"`

|               |                      |
| :------------ | :-----------------   |
| type          | `string` `string[]` |
| default       | --                    |
| commands      | `push` `pull`   |

<rem025/>
```ts
import { defineConfig } from "drizzle-kit";

export default defineConfig({
  dialect: "sqlite",
  tablesFilter: ["users", "posts", "project1_*"],
});
```

## ---

### `verbose`
<rem025/>

Print all SQL statements during `drizzle-kit push` command.

|               |                      |
| :------------ | :-----------------   |
| type          | `boolean` |
| default       | `false`                    |
| commands      | `pull`   |

<rem025/>

```ts
export default defineConfig({
  dialect: "sqlite",
  verbose: false,
});
```

### `breakpoints`
<rem025/>

Drizzle Kit will automatically embed `--> statement-breakpoint` into generated SQL migration files, 
that's necessary for databases that do not support multiple DDL alternation statements in one transaction(MySQL and SQLite).

`breakpoints` option flag lets you switch it on and off

|               |                      |
| :------------ | :-----------------   |
| type          | `boolean` |
| default       | `true`                    |
| commands      | `generate` `pull`   |

<rem025/>

```ts
export default defineConfig({
  dialect: "sqlite",
  breakpoints: false,
});
```


Source: https://orm.drizzle.team/docs/sqlite/drizzle-kit-check

import CodeTab from "@mdx/CodeTab.astro";
import CodeTabs from "@mdx/CodeTabs.astro";
import Section from "@mdx/Section.astro";
import Tab from "@mdx/Tab.astro";
import Tabs from "@mdx/Tabs.astro";
import Callout from "@mdx/Callout.astro";
import Prerequisites from "@mdx/Prerequisites.astro";
import Npm from "@mdx/Npm.astro";
import Npx from "@mdx/Npx.astro";
import Dialects from "@mdx/Dialects.mdx"

# `drizzle-kit check`

<Prerequisites>
- Get started with Drizzle and `drizzle-kit` - [read here](/docs/sqlite/get-started)
- Drizzle schema fundamentals - [read here](/docs/sqlite/sql-schema-declaration)
- Database connection basics - [read here](/docs/sqlite/connect-overview)
- Drizzle migrations fundamentals - [read here](/docs/sqlite/migrations)
- Drizzle Kit [overview](/docs/sqlite/kit-overview) and [config file](/docs/sqlite/drizzle-config-file)
- `drizzle-kit generate` command - [read here](/docs/sqlite/drizzle-kit-generate)
</Prerequisites>

`drizzle-kit check` command lets you check consistency of your generated SQL migrations history.

That's extremely useful when you have multiple developers working on the project and 
altering database schema on different branches - read more about [migrations for teams](/docs/sqlite/kit-migrations-for-teams).

<br/>
<hr/>
<br/>

`drizzle-kit check` command requires you to specify `dialect`, 
you can provide it either via [drizzle.config.ts](/docs/sqlite/drizzle-config-file) config file or via CLI options

<CodeTabs items={["With config file", "As CLI options"]}>
<Section>
```ts {5,8}
// drizzle.config.ts
import { defineConfig } from "drizzle-kit";

export default defineConfig({
  dialect: "sqlite",
});
```
```shell
npx drizzle-kit check
```
</Section>
```shell
npx drizzle-kit check --dialect=sqlite
```
</CodeTabs>

### Multiple configuration files in one project
You can have multiple config files in the project, it's very useful when you have multiple database stages or multiple databases on the same project:
<Npx>
  drizzle-kit check --config=drizzle-dev.config.ts
  drizzle-kit check --config=drizzle-prod.config.ts
</Npx>
```plaintext {5-6}
📦 <project root>
 ├ 📂 drizzle
 ├ 📂 src
 ├ 📜 .env
 ├ 📜 drizzle-dev.config.ts
 ├ 📜 drizzle-prod.config.ts
 ├ 📜 package.json
 └ 📜 tsconfig.json
```

### Ignore conflicts

In case you need `check` command to skip commutativity checks and bypass it, you can use `--ignore-conflicts`. If there is a situation you want to use it, then
there is a big chance that `drizzle-kit` didn't check migrations right and it's a bug. Please report us your case, so we can fix it

```shell
drizzle-kit check --ignore-conflicts
```

### Extended list of configurations
We recommend configuring `drizzle-kit` through [drizzle.config.ts](/docs/sqlite/drizzle-config-file) file, 
yet you can provide all configuration options through CLI if necessary, e.g. in CI/CD pipelines, etc.
<rem025/>
|           |            |                                                                         |
| :-------- | :--------- | :---------------------------------------------------------------------- |
| `dialect` | `required` | Database dialect you are using. Can be one of <Dialects/> |
| `out`     |            | Migrations folder, default=`./drizzle`                                  |
| `config`  |            | Configuration file path, default=`drizzle.config.ts`                           |
<br/>
<Npx>
drizzle-kit check --dialect=sqlite
drizzle-kit check --dialect=sqlite --out=./migrations-folder
</Npx>


Source: https://orm.drizzle.team/docs/sqlite/drizzle-kit-export

import CodeTab from "@mdx/CodeTab.astro";
import CodeTabs from "@mdx/CodeTabs.astro";
import Section from "@mdx/Section.astro";
import Tab from "@mdx/Tab.astro";
import Tabs from "@mdx/Tabs.astro";
import Callout from "@mdx/Callout.astro";
import Prerequisites from "@mdx/Prerequisites.astro"
import Npx from "@mdx/Npx.astro";
import SchemaFilePaths from "@mdx/SchemaFilePaths.mdx"
import Dialects from "@mdx/Dialects.mdx"

# `drizzle-kit export` 

<Prerequisites>
- Get started with Drizzle and `drizzle-kit` - [read here](/docs/sqlite/get-started)
- Drizzle schema fundamentals - [read here](/docs/sqlite/sql-schema-declaration)
- Database connection basics - [read here](/docs/sqlite/connect-overview)
- Drizzle migrations fundamentals - [read here](/docs/sqlite/migrations)
- Drizzle Kit [overview](/docs/sqlite/kit-overview) and [config file](/docs/sqlite/drizzle-config-file)
</Prerequisites>


<br/>

`drizzle-kit export` lets you export SQL representation of Drizzle schema and print in console SQL DDL representation on it.
<Callout collapsed="How it works under the hood?">
Drizzle Kit `export` command triggers a sequence of events:
1. It will read through your Drizzle schema file(s) and compose a json snapshot of your schema
2. Based on the current json snapshot it will generate SQL DDL statements
3. Output SQL DDL statements to console
</Callout>

It's designed to cover [codebase first](/docs/sqlite/migrations) approach of managing Drizzle migrations. 
You can export the SQL representation of the Drizzle schema, allowing external tools like Atlas to handle all the migrations for you

`drizzle-kit export` command requires you to provide both `dialect` and `schema` path options, 
you can set them either via [drizzle.config.ts](/docs/sqlite/drizzle-config-file) config file or via CLI options
<CodeTabs items={["With config file", "As CLI options"]}>
<Section>
```ts
// drizzle.config.ts
import { defineConfig } from "drizzle-kit";

export default defineConfig({
  dialect: "sqlite",
  schema: "./src/schema.ts",
});
```
```shell
npx drizzle-kit export
```
</Section>

```shell
npx drizzle-kit export --dialect=sqlite --schema=./src/schema.ts
```
</CodeTabs>

### Schema files path
You can have a single `schema.ts` file or as many schema files as you want spread out across the project. 
Drizzle Kit requires you to specify path(s) to them as a [glob](https://www.digitalocean.com/community/tools/glob?comments=true&glob=/**/*.js&matches=false&tests=//%20This%20will%20match%20as%20it%20ends%20with%20'.js'&tests=/hello/world.js&tests=//%20This%20won't%20match!&tests=/test/some/globs) via `schema` configuration option.

<SchemaFilePaths/>

### Multiple configuration files in one project
You can have multiple config files in the project, it's very useful when you have multiple database stages or multiple databases or different databases on the same project:
<Npx>
  drizzle-kit export --config=drizzle-dev.config.ts
  drizzle-kit export --config=drizzle-prod.config.ts
</Npx>
```plaintext {5-6}
📦 <project root>
 ├ 📂 drizzle
 ├ 📂 src
 ├ 📜 .env
 ├ 📜 drizzle-dev.config.ts
 ├ 📜 drizzle-prod.config.ts
 ├ 📜 package.json
 └ 📜 tsconfig.json
```

### Extended list of available configurations
`drizzle-kit export` has a list of cli-only options

<rem025/>

|               |                                                      |
| :--------     | :--------------------------------------------------- |
| `--sql`       | generating SQL representation of Drizzle Schema               |

By default, Drizzle Kit outputs SQL files, but in the future, we want to support different formats

<rem025/>

<Npx>
drizzle-kit export --sql=true
</Npx>

<br/>
<hr/>
<br/>
We recommend configuring `drizzle-kit` through [drizzle.config.ts](/docs/sqlite/drizzle-config-file) file, 
yet you can provide all configuration options through CLI if necessary, e.g. in CI/CD pipelines, etc.

|               |            |                                                                            |
| :------------ | :-------   | :----------------------------------------------------------------------    |
| `dialect`     | `required` | Database dialect, one of <Dialects/>                                       |
| `schema`      | `required` | Path to typescript schema file(s) or folder(s) with multiple schema files  |
| `config`      |            | Configuration file path, default is `drizzle.config.ts`                    |

### Example
Example of how to export drizzle schema to console with Drizzle schema located in `./src/schema.ts`

We will also place drizzle config file in the `configs` folder.

Let's create config file:

```plaintext {4}
📦 <project root>
 ├ 📂 configs
 │ └ 📜 drizzle.config.ts
 ├ 📂 src
 │ └ 📜 schema.ts
 └ …
```
```ts filename='drizzle.config.ts'
import { defineConfig } from "drizzle-kit";

export default defineConfig({
  dialect: "sqlite",
  schema: "./src/schema.ts",
});
```

```ts filename='schema.ts'
import { sqliteTable, integer, text } from 'drizzle-orm/sqlite-core'

export const users = sqliteTable('users', {
	id: integer().primaryKey({ autoIncrement: true }),
	email: text().notNull(),
	name: text()
});
```

Now let's run
```shell
npx drizzle-kit export --config=./configs/drizzle.config.ts
```
And it will successfully output SQL representation of drizzle schema
```bash
CREATE TABLE `users` (
        `id` integer PRIMARY KEY AUTOINCREMENT,
        `email` text NOT NULL,
        `name` text
);
```

Source: https://orm.drizzle.team/docs/sqlite/drizzle-kit-generate

import CodeTab from "@mdx/CodeTab.astro";
import CodeTabs from "@mdx/CodeTabs.astro";
import Section from "@mdx/Section.astro";
import Tab from "@mdx/Tab.astro";
import Tabs from "@mdx/Tabs.astro";
import Callout from "@mdx/Callout.astro";
import Prerequisites from "@mdx/Prerequisites.astro"
import Npx from "@mdx/Npx.astro";
import SchemaFilePaths from "@mdx/SchemaFilePaths.mdx"
import Dialects from "@mdx/Dialects.mdx"

# `drizzle-kit generate` 

<Prerequisites>
- Get started with Drizzle and `drizzle-kit` - [read here](/docs/sqlite/get-started)
- Drizzle schema fundamentals - [read here](/docs/sqlite/sql-schema-declaration)
- Database connection basics - [read here](/docs/sqlite/connect-overview)
- Drizzle migrations fundamentals - [read here](/docs/sqlite/migrations)
- Drizzle Kit [overview](/docs/sqlite/kit-overview) and [config file](/docs/sqlite/drizzle-config-file)
</Prerequisites>


<br/>

`drizzle-kit generate` lets you generate SQL migrations based on your Drizzle schema upon declaration or on subsequent schema changes.
<Callout collapsed="How it works under the hood?">
Drizzle Kit `generate` command triggers a sequence of events:
1. It will read through your Drizzle schema file(s) and compose a json snapshot of your schema
2. It will read through your previous migrations folders and compare current json snapshot to the most recent one
3. Based on json differences it will generate SQL migrations
4. Save `migration.sql` and `snapshot.json` in migration folder under current timestamp

<Section>
```typescript filename="src/schema.ts"
import * as p from "drizzle-orm/sqlite-core";

export const users = p.sqliteTable("users", {
  id: p.integer().primaryKey({ autoIncrement: true }),
  name: p.text(),
  email: p.text().unique(), 
});
```
```                                  
┌────────────────────────┐                  
│ $ drizzle-kit generate │                  
└─┬──────────────────────┘                  
  │                                           
  └ 1. read previous migration folders
    2. find diff between current and previous schema
    3. prompt developer for renames if necessary
  ┌ 4. generate SQL migration and persist to file
  │    ┌─┴───────────────────────────────────────┐  
  │      📂 drizzle       
  │      └ 📂 20242409125510_premium_mister_fear
  │        ├ 📜 migration.sql
  │        └ 📜 snapshot.json
  v
```
```sql
-- drizzle/20242409125510_premium_mister_fear/migration.sql

CREATE TABLE `users` (
	`id` integer PRIMARY KEY AUTOINCREMENT,
	`name` text,
	`email` text UNIQUE
);
```
</Section>
</Callout>

It's designed to cover [code first](/docs/sqlite/migrations) approach of managing Drizzle migrations. 
You can apply generated migrations using [`drizzle-kit migrate`](/docs/sqlite/drizzle-kit-migrate), using drizzle-orm's `migrate()`, 
using external migration tools like [bytebase](https://www.bytebase.com/) or running migrations yourself directly on the database. 

`drizzle-kit generate` command requires you to provide both `dialect` and `schema` path options, 
you can set them either via [drizzle.config.ts](/docs/sqlite/drizzle-config-file) config file or via CLI options
<CodeTabs items={["With config file", "As CLI options"]}>
<Section>
```ts
// drizzle.config.ts
import { defineConfig } from "drizzle-kit";

export default defineConfig({
  dialect: "sqlite",
  schema: "./src/schema.ts",
});
```
```shell
npx drizzle-kit generate
```
</Section>

```shell
npx drizzle-kit generate --dialect=sqlite --schema=./src/schema.ts
```
</CodeTabs>

### Schema files path
You can have a single `schema.ts` file or as many schema files as you want spread out across the project. 
Drizzle Kit requires you to specify path(s) to them as a [glob](https://www.digitalocean.com/community/tools/glob?comments=true&glob=/**/*.js&matches=false&tests=//%20This%20will%20match%20as%20it%20ends%20with%20'.js'&tests=/hello/world.js&tests=//%20This%20won't%20match!&tests=/test/some/globs) via `schema` configuration option.

<SchemaFilePaths/>


### Custom migration file name
You can set custom migration file names by providing `--name` CLI option
```shell
npx drizzle-kit generate --name=init
```
```plaintext {4}
📦 <project root>
 ├ 📂 drizzle
 │ └ 📂 20242409125510_init
 │   ├ 📜 snapshot.json
 │   └ 📜 migration.sql
 ├ 📂 src
 └ …
```

### Multiple configuration files in one project
You can have multiple config files in the project, it's very useful when you have multiple database stages or multiple databases or different databases on the same project:
<Npx>
  drizzle-kit generate --config=drizzle-dev.config.ts
  drizzle-kit generate --config=drizzle-prod.config.ts
</Npx>
```plaintext {5-6}
📦 <project root>
 ├ 📂 drizzle
 ├ 📂 src
 ├ 📜 .env
 ├ 📜 drizzle-dev.config.ts
 ├ 📜 drizzle-prod.config.ts
 ├ 📜 package.json
 └ 📜 tsconfig.json
```

### Custom migrations
You can generate empty migration files to write your own custom SQL migrations 
for DDL alternations currently not supported by Drizzle Kit or data seeding. Extended docs on custom migrations - [see here](/docs/sqlite/kit-custom-migrations)

```shell
drizzle-kit generate --custom --name=seed-users
```
<Section>
```plaintext {5}
📦 <project root>
 ├ 📂 drizzle
 │ ├ 📂 20242409125510_init
 │ └ 📂 20242409125510_seed-users
 ├ 📂 src
 └ …
```
```sql
-- ./drizzle/20242409125510_seed/migration.sql

INSERT INTO `users` (`name`) VALUES('Dan');
INSERT INTO `users` (`name`) VALUES('Andrew');
INSERT INTO `users` (`name`) VALUES('Dandrew');
```
</Section>

### Ignore conflicts

In case you need `generate` command to skip commutativity checks and bypass it, you can use `--ignore-conflicts`. If there is a situation you want to use it, then
there is a big chance that `drizzle-kit` didn't check migrations right and it's a bug. Please report us your case, so we can fix it

```shell
drizzle-kit generate --ignore-conflicts
```

### Extended list of available configurations
`drizzle-kit generate` has a list of cli-only options

<rem025/>

|               |                                                      |
| :--------     | :--------------------------------------------------- |
| `custom`      | generate empty SQL for custom migration              |
| `name`        | generate migration with custom name                  |
| `ignore-conflicts` | skip commutativity conflict checks, default is `false` |
<rem025/>

<Npx>
drizzle-kit generate --name=init
drizzle-kit generate --name=seed_users --custom
drizzle-kit generate --ignore-conflicts
</Npx>

<br/>
<hr/>
<br/>
We recommend configuring `drizzle-kit` through [drizzle.config.ts](/docs/sqlite/drizzle-config-file) file, 
yet you can provide all configuration options through CLI if necessary, e.g. in CI/CD pipelines, etc.

|               |            |                                                                            |
| :------------ | :-------   | :----------------------------------------------------------------------    |
| `dialect`     | `required` | Database dialect, one of <Dialects/>                                       |
| `schema`      | `required` | Path to typescript schema file(s) or folder(s) with multiple schema files  |
| `out`         |            | Migrations output folder, default is `./drizzle`                           |
| `config`      |            | Configuration file path, default is `drizzle.config.ts`                    |
| `breakpoints` |            | SQL statements breakpoints, default is `true`                              |


### Extended example
Example of how to create a custom SQLite migration file named `0001_seed-users.sql` 
with Drizzle schema located in `./src/schema.ts` and migrations folder named `./migrations` instead of default `./drizzle`.

We will also place drizzle config file in the `configs` folder.

Let's create config file:

```plaintext {4}
📦 <project root>
 ├ 📂 migrations
 ├ 📂 configs
 │ └ 📜 drizzle.config.ts
 ├ 📂 src
 └ …
```
```ts filename='drizzle.config.ts'
import { defineConfig } from "drizzle-kit";

export default defineConfig({
  dialect: "sqlite",
  schema: "./src/schema.ts",
  out: "./migrations",
});
```

Now let's run
```shell
npx drizzle-kit generate --config=./configs/drizzle.config.ts --name=seed-users --custom
```
And it will successfully generate
<Section>
```plaintext {6}
📦 <project root>
 ├ …
 ├ 📂 migrations
 │ ├ 📂 20242409125510_init
 │ └ 📂 20242409125510_seed-users
 └ …
```
```sql
-- ./drizzle/20242409125510_seed-users/migration.sql

INSERT INTO `users` (`name`) VALUES('Dan');
INSERT INTO `users` (`name`) VALUES('Andrew');
INSERT INTO `users` (`name`) VALUES('Dandrew');
```
</Section>


Source: https://orm.drizzle.team/docs/sqlite/drizzle-kit-migrate

import CodeTab from "@mdx/CodeTab.astro";
import CodeTabs from "@mdx/CodeTabs.astro";
import Section from "@mdx/Section.astro";
import Tab from "@mdx/Tab.astro";
import Tabs from "@mdx/Tabs.astro";
import Callout from "@mdx/Callout.astro";
import Prerequisites from "@mdx/Prerequisites.astro";
import Npx from "@mdx/Npx.astro";

# `drizzle-kit migrate`
<Prerequisites>
- Get started with Drizzle and `drizzle-kit` - [read here](/docs/sqlite/get-started)
- Drizzle schema fundamentals - [read here](/docs/sqlite/sql-schema-declaration)
- Database connection basics - [read here](/docs/sqlite/connect-overview)
- Drizzle migrations fundamentals - [read here](/docs/sqlite/migrations)
- Drizzle Kit [overview](/docs/sqlite/kit-overview) and [config file](/docs/sqlite/drizzle-config-file)
- `drizzle-kit generate` command - [read here](/docs/sqlite/drizzle-kit-generate)
</Prerequisites>
<br/>


`drizzle-kit migrate` lets you apply SQL migrations generated by [`drizzle-kit generate`](/docs/sqlite/drizzle-kit-generate). 
It's designed to cover [code first(option 3)](/docs/sqlite/migrations) approach of managing Drizzle migrations. 

<Callout collapsed="How it works under the hood?">
Drizzle Kit `migrate` command triggers a sequence of events:
1. Reads through migration folder and read all `.sql` migration files
2. Connects to the database and fetches entries from drizzle migrations log table
3. Based on previously applied migrations it will decide which new migrations to run
4. Runs SQL migrations and logs applied migrations to drizzle migrations table

<Section>
```plaintext
  ├ 📂 drizzle       
  │ ├ 📂 20242409125510_premium_mister_fear
  │ └ 📂 20242409135510_delicate_professor_xavie
  └ …
```
```plaintext
┌───────────────────────┐                  
│ $ drizzle-kit migrate │                  
└─┬─────────────────────┘                  
  │                                                         ┌──────────────────────────┐                                         
  └ 1. reads migration.sql files in migrations folder       │                          │
    2. fetch migration history from database -------------> │                          │
  ┌ 3. pick previously unapplied migrations <-------------- │         DATABASE         │
  └ 4. apply new migration to the database ---------------> │                          │
                                                            │                          │
                                                            └──────────────────────────┘
[✓] done!        
```
</Section>
</Callout>

`drizzle-kit migrate` command requires you to specify both `dialect` and database connection credentials, 
you can provide them either via [drizzle.config.ts](/docs/sqlite/drizzle-config-file) config file or via CLI options

<CodeTabs items={["With config file", "As CLI options"]}>
<Section>
```ts {5,8}
// drizzle.config.ts
import { defineConfig } from "drizzle-kit";

export default defineConfig({
  dialect: "sqlite",
  schema: "./src/schema.ts",
  dbCredentials: {
    url: "./sqlite.db"
  },
});
```
```shell
npx drizzle-kit migrate
```
</Section>
```shell
npx drizzle-kit migrate --dialect=sqlite --url=./sqlite.db
```
</CodeTabs>

### Applied migrations log in the database
Upon running migrations Drizzle Kit will persist records about successfully applied migrations in your database. 
It will store them in migrations log table named `__drizzle_migrations`.

You can customise the **table** name of that log table via drizzle config file:
```ts filename="drizzle.config.ts" {8-9}
export default defineConfig({
  dialect: "sqlite",
  schema: "./src/schema.ts",
  dbCredentials: {
    url: "./sqlite.db"
  },
  migrations: {
    table: 'my-migrations-table', // `__drizzle_migrations` by default
  },
});
```

### Multiple configuration files in one project
You can have multiple config files in the project, it's very useful when you have multiple database stages or multiple databases on the same project:
<Npx>
  drizzle-kit migrate --config=drizzle-dev.config.ts
  drizzle-kit migrate --config=drizzle-prod.config.ts
</Npx>
```plaintext {5-6}
📦 <project root>
 ├ 📂 drizzle
 ├ 📂 src
 ├ 📜 .env
 ├ 📜 drizzle-dev.config.ts
 ├ 📜 drizzle-prod.config.ts
 ├ 📜 package.json
 └ 📜 tsconfig.json
```

### Extended example
Let's generate SQL migration and apply it to our database using `drizzle-kit generate` and `drizzle-kit migrate` commands

```plaintext
📦 <project root>
 ├ 📂 drizzle
 ├ 📂 src
 │ ├ 📜 schema.ts
 │ └ 📜 index.ts
 ├ 📜 drizzle.config.ts
 └ …
```
<CodeTabs items={["drizzle.config.ts", "src/schema.ts"]}>
```ts
import { defineConfig } from "drizzle-kit";

export default defineConfig({
  dialect: "sqlite",
  schema: "./src/schema.ts",
  dbCredentials: {
    url: "./sqlite.db"
  },
  migrations: {
    table: 'journal', 
  },
});
```
```ts 
import * as p from "drizzle-orm/sqlite-core";

export const users = p.sqliteTable("users", {
  id: p.integer().primaryKey({ autoIncrement: true }),
  name: p.text(),
})
```
</CodeTabs>

Now let's run
```shell
npx drizzle-kit generate --name=init
```
it will generate
<Section>
```plaintext {5}
📦 <project root>
 ├ …
 ├ 📂 migrations
 │ ├ 📂 20242409125510_init
 └ …
```
```sql
-- ./drizzle/0000_init.sql

CREATE TABLE `users` (
	`id` integer PRIMARY KEY AUTOINCREMENT,
	`name` text
);
```
</Section>

Now let's run
```shell
npx drizzle-kit migrate
```

and our SQL migration is now successfully applied to the database ✅


Source: https://orm.drizzle.team/docs/sqlite/drizzle-kit-pull

import CodeTab from "@mdx/CodeTab.astro";
import CodeTabs from "@mdx/CodeTabs.astro";
import Section from "@mdx/Section.astro";
import Tab from "@mdx/Tab.astro";
import Tabs from "@mdx/Tabs.astro";
import Callout from "@mdx/Callout.astro";
import Prerequisites from "@mdx/Prerequisites.astro";
import Drivers from "@mdx/Drivers.mdx"
import Dialects from "@mdx/Dialects.mdx"
import Npm from "@mdx/Npm.astro"
import Npx from "@mdx/Npx.astro"

# `drizzle-kit pull`

<Prerequisites>
- Get started with Drizzle and `drizzle-kit` - [read here](/docs/sqlite/get-started)
- Drizzle schema fundamentals - [read here](/docs/sqlite/sql-schema-declaration) 
- Database connection basics - [read here](/docs/sqlite/connect-overview) 
- Drizzle migrations fundamentals - [read here](/docs/sqlite/migrations) 
- Drizzle Kit [overview](/docs/sqlite/kit-overview) and [config file](/docs/sqlite/drizzle-config-file) docs
</Prerequisites>

`drizzle-kit pull` lets you literally pull(introspect) your existing database schema and generate `schema.ts` drizzle schema file, 
it is designed to cover [database first](/docs/sqlite/migrations) approach of Drizzle migrations.

<Callout collapsed="How it works under the hood?">
When you run Drizzle Kit `pull` command it will:
1. Pull database schema(DDL) from your existing database
2. Generate `schema.ts` drizzle schema file and save it to `out` folder

<Section>
```
                                  ┌────────────────────────┐      ┌───────────────────────────────────────┐ 
                                  │                        │ <---  CREATE TABLE `users` (
┌──────────────────────────┐      │                        │        `id` integer primary key autoincrement,
│ ~ drizzle-kit pull       │      │                        │        `name` TEXT,
└─┬────────────────────────┘      │        DATABASE        │        `email` TEXT UNIQUE
  │                               │                        │       );
  └ Pull datatabase schema -----> │                        │
  ┌ Generate Drizzle       <----- │                        │
  │ schema TypeScript file        └────────────────────────┘
  │
  v
```
```typescript
import * as p from "drizzle-orm/sqlite-core";

export const users = p.sqliteTable("users", {
	id: p.integer().primaryKey({ autoIncrement: true }),
	name: p.text(),
	email: p.text().unique(),
});
```
</Section>
</Callout>

It is a great approach if you need to manage database schema outside of your TypeScript project or 
you're using database, which is managed by somebody else.

<br/>
<hr/>
<br/>

`drizzle-kit pull` requires you to specify `dialect` and either
database connection `url` or `user:password@host:port/db` params, you can provide them
either via [drizzle.config.ts](/docs/sqlite/drizzle-config-file) config file or via CLI options:

<CodeTabs items={["With config file", "With CLI options"]}>
<Section>
```ts
// drizzle.config.ts
import { defineConfig } from "drizzle-kit";

export default defineConfig({
  dialect: "sqlite",
  dbCredentials: {
    url: "./sqlite.db",
  },
});
```
```shell
npx drizzle-kit pull
```
</Section>

```shell
npx drizzle-kit pull --dialect=sqlite --url=./sqlite.db
```
</CodeTabs>

### Multiple configuration files in one project

You can have multiple config files in the project, it's very useful when you have multiple database stages or multiple databases or different databases on the same project:

<Npx>
  drizzle-kit pull --config=drizzle-dev.config.ts
  drizzle-kit pull --config=drizzle-prod.config.ts
</Npx>
```plaintext {5-6}
📦 <project root>
 ├ 📂 drizzle
 ├ 📂 src
 ├ 📜 .env
 ├ 📜 drizzle-dev.config.ts
 ├ 📜 drizzle-prod.config.ts
 ├ 📜 package.json
 └ 📜 tsconfig.json
```

### Specifying database driver
<Callout type="warning">
**Expo SQLite** and **OP SQLite** are on-device(per-user) databases, there's no way to `pull` database schema from there.<br/>
For embedded databases Drizzle provides **embedded migrations** - check out our [get started](/docs/get-started/expo-new) guide.
</Callout>
Drizzle Kit does not come with a pre-bundled database driver, 
it will automatically pick an available SQLite driver from your current project based on `dialect: "sqlite"` - [see discussion](https://github.com/drizzle-team/drizzle-orm/discussions/2203).

For Cloudflare D1 HTTP, specify `driver: "d1-http"` explicitly.

```ts {6}
import { defineConfig } from "drizzle-kit";

export default defineConfig({
  dialect: "sqlite",
  driver: "d1-http",
  dbCredentials: {
    accountId: "accountId",
    databaseId: "databaseId",
    token: "token",
  },
});
```

### Initial pull

You can use the `--init` flag to mark the pulled schema as an applied migration in your database, 
so that all subsequent migrations are diffed against the initial one

```shell
npx drizzle-kit push --init
```

### Including tables
`drizzle-kit pull` will introspect all SQLite tables by default.
You can configure the list of tables via `tablesFilter`.

|                |                                                                                               |
| :------------- | :-------------------------------------------------------------------------------------------- |
| `tablesFilter` | `glob` based table names filter, e.g. `["users", "user_info"]` or `"user*"`. Default is `"*"` |
<br/>

Let's configure drizzle-kit to introspect **all tables** in the SQLite database.

<Section>
```ts filename="drizzle.config.ts" {8}
import { defineConfig } from "drizzle-kit";

export default defineConfig({
  dialect: "sqlite",
  dbCredentials: {
     url: "./sqlite.db",
  },
  tablesFilter: ["*"],
});
```
```shell
npx drizzle-kit pull
```
</Section>

### Extended list of configurations
We recommend configuring `drizzle-kit` through [drizzle.config.ts](/docs/sqlite/drizzle-config-file) file, 
yet you can provide all configuration options through CLI if necessary, e.g. in CI/CD pipelines, etc.

|                     |            |                                                                           |
| :------------------ | :--------- | :------------------------------------------------------------------------ |
| `dialect`           | `required` | Database dialect, one of <Dialects/>                                      |
| `driver`            |            | Driver exception, for example `d1-http`                                   |
| `out`               |            | Migrations output folder path, default is `./drizzle`                     |
| `url`               |            | Database connection string                                                |
| `user`              |            | Database user                                                             |
| `password`          |            | Database password                                                         |
| `host`              |            | Host                                                                      |
| `port`              |            | Port                                                                      |
| `database`          |            | Database name                                                             |
| `config`            |            | Configuration file path, default is `drizzle.config.ts`                          |
| `introspect-casing` |            | Strategy for JS keys creation in columns, tables, etc. `preserve` `camel` |
| `tablesFilter`      |            | Table name filter                                                         |

<Npx>
drizzle-kit pull --dialect=sqlite --url=./sqlite.db
drizzle-kit pull --dialect=sqlite --tablesFilter='user*' url=./sqlite.db
</Npx>

{/* TODO update gif */}
![](@/assets/gifs/introspect_mysql.gif)


Source: https://orm.drizzle.team/docs/sqlite/drizzle-kit-push

import CodeTab from "@mdx/CodeTab.astro";
import CodeTabs from "@mdx/CodeTabs.astro";
import Section from "@mdx/Section.astro";
import Tab from "@mdx/Tab.astro";
import Tabs from "@mdx/Tabs.astro";
import Callout from "@mdx/Callout.astro";
import Prerequisites from "@mdx/Prerequisites.astro";
import Npx from "@mdx/Npx.astro";
import SchemaFilePaths from "@mdx/SchemaFilePaths.mdx";
import Drivers from "@mdx/Drivers.mdx"
import Dialects from "@mdx/Dialects.mdx"
import DriversExamples from "@mdx/DriversExamples.mdx"

# `drizzle-kit push`

<Prerequisites>
- Get started with Drizzle and `drizzle-kit` - [read here](/docs/sqlite/get-started)
- Drizzle schema fundamentals - [read here](/docs/sqlite/sql-schema-declaration) 
- Database connection basics - [read here](/docs/sqlite/connect-overview) 
- Drizzle migrations fundamentals - [read here](/docs/sqlite/migrations) 
- Drizzle Kit [overview](/docs/sqlite/kit-overview) and [config file](/docs/sqlite/drizzle-config-file) docs
</Prerequisites>


`drizzle-kit push` lets you literally push your schema and subsequent schema changes directly to the
database while omitting SQL files generation, it's designed to cover [code first](/docs/sqlite/migrations)
approach of Drizzle migrations.

<Callout collapsed="How it works under the hood?">
When you run Drizzle Kit `push` command it will:
1. Read through your Drizzle schema file(s) and compose a json snapshot of your schema
2. Pull(introspect) database schema 
3. Based on differences between those two it will generate SQL migrations
4. Apply SQL migrations to the database

<Section>
```typescript filename="src/schema.ts"
import * as p from "drizzle-orm/sqlite-core";

export const users = p.sqliteTable("users", {
  id: p.integer().primaryKey({ autoIncrement: true }),
  name: p.text(),
});
```
```
┌─────────────────────┐                  
│ ~ drizzle-kit push  │                  
└─┬───────────────────┘                  
  │                                           ┌──────────────────────────┐
  └ Pull current datatabase schema ---------> │                          │
                                              │                          │
  ┌ Generate alternations based on diff <---- │         DATABASE         │
  │                                           │                          │
  └ Apply migrations to the database -------> │                          │
                                       │      └──────────────────────────┘
                                       │
  ┌────────────────────────────────────┴───────────────────────────────────────┐
   CREATE TABLE `users` (`id` integer PRIMARY KEY AUTOINCREMENT, `name` text );
```
</Section>
</Callout>

It's the best approach for rapid prototyping and we've seen dozens of teams
and solo developers successfully using it as a primary migrations flow in their production applications.
It pairs exceptionally well with blue/green deployment strategy and serverless databases like
[Planetscale](https://planetscale.com), [Neon](https://neon.tech), [Turso](https://turso.tech/drizzle) and others.

<br/>
<hr/>
<br/>


`drizzle-kit push` requires you to specify `dialect`, path to the `schema` file(s) and either
database connection `url` or `user:password@host:port/db` params, you can provide them
either via [drizzle.config.ts](/docs/sqlite/drizzle-config-file) config file or via CLI options:

<CodeTabs items={["With config file", "With CLI options"]}>
<Section>
```ts
// drizzle.config.ts
import { defineConfig } from "drizzle-kit";

export default defineConfig({
  dialect: "sqlite",
  schema: "./src/schema.ts",
  dbCredentials: {
    url: "./sqlite.db",
  },
});
```
```shell
npx drizzle-kit push
```
</Section>

```shell
npx drizzle-kit push --dialect=sqlite --schema=./src/schema.ts --url=./sqlite.db
```

</CodeTabs>

### Schema files path

You can have a single `schema.ts` file or as many schema files as you want spread out across the project.
Drizzle Kit requires you to specify path(s) to them as a [glob](https://www.digitalocean.com/community/tools/glob?comments=true&glob=/**/*.js&matches=false&tests=//%20This%20will%20match%20as%20it%20ends%20with%20'.js'&tests=/hello/world.js&tests=//%20This%20won't%20match!&tests=/test/some/globs) via `schema` configuration option.

<SchemaFilePaths />

### Multiple configuration files in one project

You can have multiple config files in the project, it's very useful when you have multiple database stages or multiple databases or different databases on the same project:

<Npx>
  drizzle-kit push --config=drizzle-dev.config.ts
  drizzle-kit push --config=drizzle-prod.config.ts
</Npx>
```plaintext {5-6}
📦 <project root>
 ├ 📂 drizzle
 ├ 📂 src
 ├ 📜 .env
 ├ 📜 drizzle-dev.config.ts
 ├ 📜 drizzle-prod.config.ts
 ├ 📜 package.json
 └ 📜 tsconfig.json
```

### Specifying database driver
<Callout type="warning">
**Expo SQLite** and **OP SQLite** are on-device(per-user) databases, there's no way to `push` migrations there.<br/>
For embedded databases Drizzle provides **embedded migrations** - check out our [get started](/docs/get-started/expo-new) guide.
</Callout>
Drizzle Kit does not come with a pre-bundled database driver, 
it will automatically pick an available SQLite driver from your current project based on the `dialect` - [see discussion](https://github.com/drizzle-team/drizzle-orm/discussions/2203).

For Cloudflare D1 HTTP, specify `driver: "d1-http"` explicitly.

```ts {6}
import { defineConfig } from "drizzle-kit";

export default defineConfig({
  dialect: "sqlite",
  driver: "d1-http",
  dbCredentials: {
    accountId: "accountId",
    databaseId: "databaseId",
    token: "token",
  },
});
```

### Including tables
`drizzle-kit push` will manage all SQLite tables by default.
You can configure the list of tables via `tablesFilter`.

|                |                                                                                               |
| :------------- | :-------------------------------------------------------------------------------------------- |
| `tablesFilter` | `glob` based table names filter, e.g. `["users", "user_info"]` or `"user*"`. Default is `"*"` |
<br/>

Let's configure drizzle-kit to operate with **all tables** in the SQLite database.

<Section>
```ts filename="drizzle.config.ts" {9}
import { defineConfig } from "drizzle-kit";

export default defineConfig({
  dialect: "sqlite",
  schema: "./src/schema.ts",
  dbCredentials: {
    url: "./sqlite.db",
  },
  tablesFilter: ["*"],
});
```
```shell
npx drizzle-kit push
```
</Section>

### Extended list of configurations

`drizzle-kit push` has a list of cli-only options

<rem025/>

|           |                                                                 |
| :-------- | :---------------------------------------------------------------|
| `verbose` | print all SQL statements prior to execution                     |
| `explain` | print the planned SQL changes, without applying them (dry run)  |
| `force`   | auto-accept all data-loss statements                            |
<br/>
<Npx>
drizzle-kit push --explain --verbose --force
</Npx>

<br/>
<hr/>
<br/>
We recommend configuring `drizzle-kit` through [drizzle.config.ts](/docs/sqlite/drizzle-config-file) file, 
yet you can provide all configuration options through CLI if necessary, e.g. in CI/CD pipelines, etc.

|                     |            |                                                                           |
| :------------------ | :--------- | :------------------------------------------------------------------------ |
| `dialect`           | `required` | Database dialect, one of <Dialects/>                                      |
| `schema`            | `required` | Path to typescript schema file(s) or folder(s) with multiple schema files |
| `driver`            |            | Driver exception, for example `d1-http`                                   |
| `tablesFilter`      |            | Table name filter                                                         |
| `url`               |            | Database connection string                                                |
| `user`              |            | Database user                                                             |
| `password`          |            | Database password                                                         |
| `host`              |            | Host                                                                      |
| `port`              |            | Port                                                                      |
| `database`          |            | Database name                                                             |
| `config`            |            | Configuration file path, default=`drizzle.config.ts`                             |

<Npx>
drizzle-kit push dialect=sqlite schema=src/schema.ts url=./sqlite.db
drizzle-kit push dialect=sqlite schema=src/schema.ts --tablesFilter='user*' url=./sqlite.db
</Npx>


### Extended example
Let's declare drizzle schema in the project and push it to the database via `drizzle-kit push` command

```plaintext
📦 <project root>
 ├ 📂 src
 │ ├ 📜 schema.ts
 │ └ 📜 index.ts
 ├ 📜 drizzle.config.ts
 └ …
```
<CodeTabs items={["drizzle.config.ts", "src/schema.ts"]}>
```ts
import { defineConfig } from "drizzle-kit";

export default defineConfig({
  dialect: "sqlite",
  schema: "./src/schema.ts",
  dbCredentials: {
    url: "./sqlite.db"
  },
});
```
```ts 
import * as p from "drizzle-orm/sqlite-core";

export const users = p.sqliteTable("users", {
  id: p.integer().primaryKey({ autoIncrement: true }),
  name: p.text(),
})
```
</CodeTabs>

Now let's run
```shell
npx drizzle-kit push
```

it will pull existing(empty) schema from the database and generate SQL migration and apply it under the hood
```sql
CREATE TABLE `users`(
  `id` integer primary key autoincrement,
  `name` text
)
```

DONE ✅


Source: https://orm.drizzle.team/docs/sqlite/drizzle-kit-studio

import CodeTab from "@mdx/CodeTab.astro";
import CodeTabs from "@mdx/CodeTabs.astro";
import Section from "@mdx/Section.astro";
import Tab from "@mdx/Tab.astro";
import Tabs from "@mdx/Tabs.astro";
import Callout from "@mdx/Callout.astro";
import Prerequisites from "@mdx/Prerequisites.astro";
import Npm from "@mdx/Npm.astro";
import Npx from "@mdx/Npx.astro";


# `drizzle-kit studio`
<Prerequisites>
- Drizzle Kit [overview](/docs/sqlite/kit-overview) and [config file](/docs/sqlite/drizzle-config-file)
- Drizzle Studio, our database browser - [read here](/drizzle-studio/overview)
</Prerequisites>

`drizzle-kit studio` command spins up a server for [Drizzle Studio](/drizzle-studio/overview) hosted on [local.drizzle.studio](https://local.drizzle.studio). 
It requires you to specify database connection credentials via [drizzle.config.ts](/docs/sqlite/drizzle-config-file) config file.

By default it will start a Drizzle Studio server on `127.0.0.1:4983`
<Section>
```ts {6}
// drizzle.config.ts
import { defineConfig } from "drizzle-kit";

export default defineConfig({
  dialect: "sqlite",
  dbCredentials: {
    url: "./sqlite.db"
  },
});
```
```shell
npx drizzle-kit studio
```
</Section>

### Configuring `host` and `port`
By default Drizzle Studio server starts on `127.0.0.1:4983`, 
you can config `host` and `port` via CLI options

<Npx>
drizzle-kit studio --port=3000
drizzle-kit studio --host=0.0.0.0
drizzle-kit studio --host=0.0.0.0 --port=3000
</Npx>


### Logging
You can enable logging of every SQL statement by providing `verbose` flag

<Npx>
drizzle-kit studio --verbose
</Npx>

### Safari and Brave support
Safari and Brave block access to localhost by default. 
You need to install [mkcert](https://github.com/FiloSottile/mkcert) and generate self-signed certificate:

1. Follow the mkcert [installation steps](https://github.com/FiloSottile/mkcert#installation)
2. Run `mkcert -install`
3. Restart your `drizzle-kit studio`

### Other flavours of Drizzle Studio
Apart from `drizzle-kit studio` for local development, Drizzle Studio also comes as a self-hosted
Drizzle Gateway, a Chrome extension for serverless database vendors and an embeddable component
for your own product — check out the [Drizzle Studio overview](/drizzle-studio/overview).

### Limitations
Our hosted version Drizzle Studio is meant to be used for local development and not meant to be used on remote (VPS, etc).

If you want to deploy Drizzle Studio to your VPS — that's what
[Drizzle Gateway](/drizzle-studio/overview#drizzle-gateway) is for.

### Is it open source?
No. Drizzle ORM and Drizzle Kit are fully open sourced, while Studio is not. 

Drizzle Studio for local development is free to use forever to enrich Drizzle ecosystem, 
open sourcing one would've break our ability to provide B2B offerings and monetise it, unfortunately.


Source: https://orm.drizzle.team/docs/sqlite/drizzle-kit-up

import CodeTab from "@mdx/CodeTab.astro";
import CodeTabs from "@mdx/CodeTabs.astro";
import Section from "@mdx/Section.astro";
import Tab from "@mdx/Tab.astro";
import Tabs from "@mdx/Tabs.astro";
import Callout from "@mdx/Callout.astro";
import Prerequisites from "@mdx/Prerequisites.astro";
import Npx from "@mdx/Npx.astro";
import Dialects from "@mdx/Dialects.mdx"

# `drizzle-kit up`

<Prerequisites>
- Get started with Drizzle and `drizzle-kit` - [read here](/docs/sqlite/get-started)
- Drizzle schema fundamentals - [read here](/docs/sqlite/sql-schema-declaration)
- Database connection basics - [read here](/docs/sqlite/connect-overview)
- Drizzle migrations fundamentals - [read here](/docs/sqlite/migrations)
- Drizzle Kit [overview](/docs/sqlite/kit-overview) and [config file](/docs/sqlite/drizzle-config-file)
- `drizzle-kit generate` command - [read here](/docs/sqlite/drizzle-kit-generate)
</Prerequisites>

`drizzle-kit up` command lets you upgrade drizzle schema snapshots to a newer version. 
It's required whenever we introduce breaking changes to the json snapshots of the schema and upgrade the internal version.

<br/>
<hr/>
<br/>

`drizzle-kit up` command requires you to specify `dialect` param,
you can provide it either via [drizzle.config.ts](/docs/sqlite/drizzle-config-file) config file or via CLI options

<CodeTabs items={["With config file", "As CLI options"]}>
<Section>
```ts {5,8}
// drizzle.config.ts
import { defineConfig } from "drizzle-kit";

export default defineConfig({
  dialect: "sqlite",
});
```
```shell
npx drizzle-kit up
```
</Section>
```shell
npx drizzle-kit up --dialect=sqlite
```
</CodeTabs>

### Multiple configuration files in one project
You can have multiple config files in the project, it's very useful when you have multiple database stages or multiple databases on the same project:
<Npx>
  drizzle-kit migrate --config=drizzle-dev.config.ts
  drizzle-kit migrate --config=drizzle-prod.config.ts
</Npx>
```plaintext {5-6}
📦 <project root>
 ├ 📂 drizzle
 ├ 📂 src
 ├ 📜 .env
 ├ 📜 drizzle-dev.config.ts
 ├ 📜 drizzle-prod.config.ts
 ├ 📜 package.json
 └ 📜 tsconfig.json
```

### Extended list of configurations
We recommend configuring `drizzle-kit` through [drizzle.config.ts](/docs/sqlite/drizzle-config-file) file, 
yet you can provide all configuration options through CLI if necessary, e.g. in CI/CD pipelines, etc.
<rem025/>
|           |            |                                                                         |
| :-------- | :--------- | :---------------------------------------------------------------------- |
| `dialect` | `required` | Database dialect you are using. Can be one of <Dialects/> |
| `out`     |            | Migrations folder, default=`./drizzle`                                  |
| `config`  |            | Configuration file path, default=`drizzle.config.ts`                           |
<br/>
<Npx>
drizzle-kit up --dialect=sqlite
drizzle-kit up --dialect=sqlite --out=./migrations-folder
</Npx>

{/* TODO: update up gif */}
![](@/assets/gifs/up_mysql.gif)


Source: https://orm.drizzle.team/docs/sqlite/dynamic-query-building

import Callout from '@mdx/Callout.astro';

# Dynamic query building

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
```

In the previous ORM versions, when such restrictions weren't implemented, this example in particular was a source of confusion for many users, as they expected the query builder to "merge" multiple `.where()` calls into a single condition.

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 SQLiteSelect>(
	qb: T,
	page: number = 1,
	pageSize: number = 10,
) {
	return qb.limit(pageSize).offset((page - 1) * 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 SQLiteSelect>(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);
```

This is possible, because `SQLiteSelect` and other similar types are specifically designed to be used in dynamic query building. They can only be used in dynamic mode.

Here is the list of all types that can be used as generic parameters in dynamic query building:

| Query  | Type                              |
|:--------|:-----------------------------------|
| Select | `SQLiteSelect` / `SQLiteSelectQueryBuilder` |
| Insert | `SQLiteInsert`                        |
| Update | `SQLiteUpdate`                        |
| Delete | `SQLiteDelete`                        |

<Callout type='info'>
	The `...QueryBuilder` types are for usage with [standalone query builder
	instances](/docs/sqlite/goodies#standalone-query-builder). DB query builders are
	subclasses of them, so you can use them as well.

    ```ts
    	import { QueryBuilder } from 'drizzle-orm/sqlite-core';

    	function withFriends<T extends SQLiteSelectQueryBuilder>(qb: T) {
    		return qb.leftJoin(friends, eq(friends.userId, users.id));
    	}

    	const qb = new QueryBuilder();
    	let query = qb.select().from(users).where(eq(users.id, 1)).$dynamic();
    	query = withFriends(query);
    ```
</Callout>


Source: https://orm.drizzle.team/docs/sqlite/effect-schema

import Npm from '@mdx/Npm.astro';
import Callout from '@mdx/Callout.astro';

# effect-schema

Allows you to generate [effect](https://effect.website/) schemas from Drizzle ORM schemas.

**Features**

- Create a select schema for tables and views.
- Create insert and update schemas for tables.
- Supported dialect: SQLite.

#### Usage

```ts
import { integer, sqliteTable, text } from 'drizzle-orm/sqlite-core';
import { createInsertSchema, createSelectSchema, createUpdateSchema } from 'drizzle-orm/effect-schema';
import { Effect, Schema } from 'effect';

const users = sqliteTable('users', {
	id: integer().primaryKey({ autoIncrement: true }),
	name: text().notNull(),
	email: text().notNull(),
	role: text({ enum: ['admin', 'user'] }).notNull(),
	createdAt: integer('created_at', { mode: 'timestamp' }).notNull(),
});

// Schema for inserting a user - can be used to validate API requests
const UserInsert = createInsertSchema(users);

// Schema for updating a user - can be used to validate API requests
const UserUpdate = createUpdateSchema(users);

// Schema for selecting a user - can be used to validate API responses
const UserSelect = createSelectSchema(users);

// Overriding the fields
const UserInsert = createInsertSchema(users, {
	role: Schema.String,
});

// Refining the fields - useful if you want to change the fields before they become nullable/optional in the final schema
const UserInsert = createInsertSchema(users, {
	id: (schema) => schema.check(Schema.isGreaterThanOrEqualTo(0)),
	role: Schema.String,
});

// Usage

const program = Effect.gen(function*() {
	const parsedUser = yield* Schema.decodeUnknownEffect(UserInsert)({
		name: 'John Doe',
		email: 'johndoe@test.com',
		role: 'admin',
	});
});
```

Source: https://orm.drizzle.team/docs/sqlite/extensions


import Callout from '@mdx/Callout.astro';

<Callout>
Currently, there are no SQLite extensions natively supported by Drizzle. Once those are added, we will have them here!
</Callout>

Source: https://orm.drizzle.team/docs/sqlite/generated-columns

import CodeTabs from '@mdx/CodeTabs.astro';
import CodeTab from '@mdx/CodeTab.astro';
import Callout from '@mdx/Callout.astro';

# Generated Columns

1. Virtual (or non-persistent) Generated Columns: These columns are computed dynamically whenever they are queried. They do not occupy storage space in the database.

2. Stored (or persistent) Generated Columns: These columns are computed when a row is inserted or updated and their values are stored in the database. This allows them to be indexed and can improve query performance since the values do not need to be recomputed for each query.

#### Database side
    **Types**: `STORED`, `VIRTUAL`

    **How It Works**
    - Defined with an expression in the table schema.
    - Virtual columns are computed during read operations.
    - Stored columns are computed during write operations and stored.

    **Capabilities**
    - Used in SELECT, INSERT, UPDATE, and DELETE statements.
    - Can be indexed, both virtual and stored.
    - Can specify NOT NULL and other constraints.
    
    **Limitations**
    - Cannot directly insert or update values in a generated column 

    For more info, please check [SQLite](https://www.sqlite.org/gencol.html) docs 

    #### Drizzle side
    In Drizzle you can specify `.generatedAlwaysAs()` function on any column type and add a supported sql query, 
    that will generate this column data for you.

    #### Features 
    This function can accept generated expression in 2 ways:

    **`sql`** tag - if you want drizzle to escape some values for you

    ```ts
    export const test = sqliteTable("test", {
        id: int().primaryKey(),
        generatedName: text("gen_name").generatedAlwaysAs(sql`'hello "world"!'`),
    });
    ```
    ```sql
    CREATE TABLE `test` (
      `id` integer PRIMARY KEY,
      `gen_name` text GENERATED ALWAYS AS ('hello "world"!') VIRTUAL
    );
    ```

    **`callback`** - if you need to reference columns from a table

    ```ts
    export const test = sqliteTable("test", {
        name: text("first_name"),
        generatedName: text("gen_name").generatedAlwaysAs(
          (): SQL => sql`'hi,' || ${test.name} || '!'`
        ),
    });
    ```
    ```sql
    CREATE TABLE `test` (
      `first_name` text,
      `gen_name` text GENERATED ALWAYS AS ('hi,' || "first_name" || '!') VIRTUAL
    );
    ```

    #### Behavior in Drizzle Kit
	`push` and `generate` command:
    1. Changing the generated expression on a `stored` column in an existing table will cause table recreation. (Changing a `virtual` expression will cause column recreation).
    2. Adding a `stored` generated expression to an existing column will cause table recreation. (Adding a `virtual` expression to an existing column will cause column recreation).
    3. Changing the generated mode from `virtual` to `stored` will cause table recreation. (Switching from `stored` to `virtual` will cause column recreation).

  <CodeTabs items={["schema.ts"]}>
	<CodeTab>
	```typescript copy
    export const users = sqliteTable("users", {
      id: int(),
      name: text(),
      storedGenerated: text("stored_gen").generatedAlwaysAs(
        (): SQL => sql`${users.name} || 'hello'`,
        { mode: "stored" }
      ),
      virtualGenerated: text("virtual_gen").generatedAlwaysAs(
        (): SQL => sql`${users.name} || 'hello'`,
        { mode: "virtual" }
      ),
    });
    ```
    ```sql
    CREATE TABLE `users` (
	    `id` integer,
	    `name` text,
	    `stored_gen` text GENERATED ALWAYS AS ("name" || 'hello') STORED,
	    `virtual_gen` text GENERATED ALWAYS AS ("name" || 'hello') VIRTUAL
    );
    ```
    </CodeTab>
  </CodeTabs>


Source: https://orm.drizzle.team/docs/sqlite/get-started-sqlite

import Npm from "@mdx/Npm.astro";
import Callout from '@mdx/Callout.astro';
import AnchorCards from '@mdx/AnchorCards.astro';
import Steps from '@mdx/Steps.astro';
import Prerequisites from "@mdx/Prerequisites.astro";
import CodeTabs from "@mdx/CodeTabs.astro";
import WhatsNextSQLite from "@mdx/WhatsNextSQLite.astro";
import LibsqlTable from '@mdx/LibsqlTable.mdx';
import LibsqlTabs from '@mdx/LibsqlTabs.mdx';

# Drizzle \<\> SQLite

Drizzle has native support for SQLite connections with the `libsql`, `node:sqlite` and `better-sqlite3` drivers.
  
There are a few differences between the `libsql` and `node:sqlite`/`better-sqlite3` drivers that we discovered while using both and integrating them with the Drizzle ORM. For example:

At the driver level, there may not be many differences between the two, but the main one is that `libSQL` can connect to both SQLite files and `Turso` remote databases. LibSQL is a fork of SQLite that offers a bit more functionality compared to standard SQLite, such as:

- More ALTER statements are available with the `libSQL` driver, allowing you to manage your schema more easily than with just `better-sqlite3`.
- You can configure the encryption at rest feature natively.
- A large set of extensions supported by the SQLite database is also supported by `libSQL`.

## libsql
#### Step 1 - Install packages
<Npm>
 drizzle-orm@rc @libsql/client
 -D drizzle-kit@rc
</Npm>

#### Step 2 - Initialize the driver
Drizzle has native support for all @libsql/client driver variations:

<LibsqlTable />
<br/>
<LibsqlTabs />

#### Step 3 - make a query
<CodeTabs items={["libsql", "libsql with config"]}>
```typescript copy
import { drizzle } from 'drizzle-orm/libsql';

const db = drizzle(process.env.DATABASE_URL);
 
const result = await db.all('select 1');
```
```typescript copy
import { drizzle } from 'drizzle-orm/libsql';

// You can specify any property from the libsql connection options
const db = drizzle({ connection: { url:'', authToken: '' }});
 
const result = await db.all('select 1');
```
</CodeTabs>

If you need a synchronous connection, you can use our additional connection API, 
where you specify a driver connection and pass it to the Drizzle instance.

```typescript copy
import { drizzle } from 'drizzle-orm/libsql';
import { createClient } from '@libsql/client';

const client = createClient({ url: process.env.DATABASE_URL, authToken: process.env.DATABASE_AUTH_TOKEN });
const db = drizzle({ client });

const result = await db.all('select 1');
```

## node:sqlite
#### Step 1 - Install packages
<Npm>
 drizzle-orm@rc
 -D drizzle-kit@rc
</Npm>

#### Step 2 - Initialize the driver and make a query
<CodeTabs items={["node:sqlite", "node:sqlite with config"]}>
```typescript copy
import { drizzle } from 'drizzle-orm/node-sqlite';

const db = drizzle(process.env.DB_FILE_NAME);

const result = await db.execute('select 1');
```
```typescript copy
import { drizzle } from 'drizzle-orm/node-sqlite';

// You can specify any property from the node-sqlite connection options
const db =  drizzle({ connection: { path: process.env.DB_FILE_NAME }});

const result = await db.execute('select 1');
```
</CodeTabs>

If you need to provide your existing driver:
```typescript copy
import { drizzle } from 'drizzle-orm/node-sqlite';
import { DatabaseSync } from 'node:sqlite';

const sqlite = new DatabaseSync('sqlite.db');
const db = drizzle({ client: sqlite });

const result = await db.execute('select 1');
```

## better-sqlite3
#### Step 1 - Install packages
<Npm>
 drizzle-orm@rc better-sqlite3
 -D drizzle-kit@rc @types/better-sqlite3
</Npm>

#### Step 2 - Initialize the driver and make a query
<CodeTabs items={["better-sqlite3", "better-sqlite3 with config"]}>
```typescript copy
import { drizzle } from 'drizzle-orm/better-sqlite3';

const db = drizzle(process.env.DB_FILE_NAME);

const result = await db.all('select 1');
```
```typescript copy
import { drizzle } from 'drizzle-orm/better-sqlite3';

// You can specify any property from the better-sqlite3 connection options
const db =  drizzle({ connection: { source: process.env.DB_FILE_NAME }});

const result = await db.all('select 1');
```
</CodeTabs>

If you need to provide your existing driver:
```typescript copy
import { drizzle } from 'drizzle-orm/better-sqlite3';
import Database from 'better-sqlite3';

const sqlite = new Database('sqlite.db');
const db = drizzle({ client: sqlite });

const result = await db.all('select 1');
```

#### What's next?

<WhatsNextSQLite/>


Source: https://orm.drizzle.team/docs/sqlite/goodies

import Callout from '@mdx/Callout.astro';
import CodeTabs from '@mdx/CodeTabs.astro';

## Type API
Use Drizzle's type helpers to infer `select` and `insert` models from a SQLite table schema.

```ts
import { integer, text, sqliteTable } from 'drizzle-orm/sqlite-core';
import { type InferSelectModel, type InferInsertModel } from 'drizzle-orm'

const users = sqliteTable('users', {
  id: integer().primaryKey({ autoIncrement: true }),
  name: text().notNull(),
});

type SelectUser = typeof users.$inferSelect;
type InsertUser = typeof users.$inferInsert;

type SelectUserAlt = InferSelectModel<typeof users>;
type InsertUserAlt = InferInsertModel<typeof users>;
```

## Logging
Enable default query logging by passing `{ logger: true }` to `drizzle`.
```typescript copy
import { drizzle } from 'drizzle-orm/...'; // driver specific

const db = drizzle({ logger: true });
```

You can change the logs destination by creating a `DefaultLogger` instance and providing a custom `writer` to it:
```typescript copy
import { DefaultLogger, type LogWriter } from 'drizzle-orm/logger';
import { drizzle } from 'drizzle-orm/...'; // driver specific

class MyLogWriter implements LogWriter {
  write(message: string) {
    // Write to file, stdout, etc.
  }
}

const logger = new DefaultLogger({ writer: new MyLogWriter() });
const db = drizzle(process.env.DB_URL, { logger });
```

You can also provide a custom logger.

```ts
import type { Logger } from 'drizzle-orm/logger';
import { drizzle } from 'drizzle-orm/...';

class MyLogger implements Logger {
  logQuery(query: string, params: unknown[]): void {
    console.log({ query, params });
  }
}

const db = drizzle(process.env.DB_URL, { logger: new MyLogger() });
```

## Multi-project schema
Use `sqliteTableCreator` to customize table names when several projects share one database.

```ts {3}
import { integer, text, sqliteTableCreator } from 'drizzle-orm/sqlite-core';

const sqliteTable = sqliteTableCreator((name) => `project1_${name}`);

const users = sqliteTable('users', {
  id: integer().primaryKey({ autoIncrement: true }),
  name: text().notNull(),
});
```
```ts {10}
import { defineConfig } from "drizzle-kit";

export default defineConfig({
  schema: "./src/schema/*",
  out: "./drizzle",
  dialect: "sqlite", 
  dbCredentials: {
    url: process.env.DATABASE_URL,
  }
  tablesFilter: ["project1_*"],
});
```

```sql
CREATE TABLE `project1_users` (
	`id` integer PRIMARY KEY AUTOINCREMENT,
	`name` text NOT NULL
);
```

## Printing SQL Query
Print generated SQL from a query with `.toSQL()`.

```ts
const query = db
  .select({ id: users.id, name: users.name })
  .from(users)
  .groupBy(users.id)
  .toSQL();
// query:
{
  sql: 'select "id", "name" from "users" group by "users"."id"',
  params: [],
}
```

## Raw SQL Queries
If you have some complex queries to execute and `drizzle-orm` can't handle them yet,
you can use the `db.run`, `db.all`, `db.values`, `db.get` methods to execute raw `parametrized` queries.

```ts
import { sql } from 'drizzle-orm';

const statement = sql`select * from ${users} where ${users.id} = ${userId}`;

const res: unknown[] = db.all(statement)
const res: unknown = db.get(statement)
const res: unknown[][] = db.values(statement)
const res: Database.RunResult = db.run(statement)
```

## Standalone Query Builder
Use the SQLite query builder without creating a database instance.

```ts
import { QueryBuilder } from 'drizzle-orm/sqlite-core';

const qb = new QueryBuilder();

const query = qb.select().from(users).where(eq(users.name, 'Dan'));
const { sql, params } = query.toSQL();
```

## Get Typed Columns
Use `getColumns` to get a typed column map, which is useful when excluding fields from a selection.

<CodeTabs items={["index.ts", "schema.ts"]}>
```ts
import { getColumns } from "drizzle-orm";
import { users } from "./schema";

const { password, role, ...rest } = getColumns(users);

await db.select({ ...rest }).from(users);
```
```ts
import { integer, text, sqliteTable } from "drizzle-orm/sqlite-core";

export const users = sqliteTable("users", {
  id: integer().primaryKey({ autoIncrement: true }),
  name: text(),
  email: text(),
  password: text(),
  role: text().$type<"admin" | "customer">(),
});
```
</CodeTabs>

## Get Table Information
Use `getTableConfig` to inspect SQLite table metadata.

```ts
import { getTableConfig, sqliteTable } from 'drizzle-orm/sqlite-core';

export const table = sqliteTable(...);

const {
  columns,
  indexes,
  foreignKeys,
  checks,
  primaryKeys,
  name,
  uniqueConstraints,
} = getTableConfig(table);
```

## Compare Object Types
Use `is()` instead of `instanceof` to check Drizzle object types.

```ts
import { Column, is } from 'drizzle-orm';

if (is(value, Column)) {
  // value's type is narrowed to Column
}
```

## Mock Driver
Use `drizzle.mock()` when you need a typed database object without a real PostgreSQL connection.

```ts
import { drizzle } from "drizzle-orm/...";
import { relations } from "./relations";

const db = drizzle.mock({ relations });
```


Source: https://orm.drizzle.team/docs/sqlite/guides/count-rows

import Section from "@mdx/Section.astro";
import Prerequisites from "@mdx/Prerequisites.astro";
import CodeTabs from '@mdx/CodeTabs.astro';
import CodeTab from '@mdx/CodeTab.astro';
import Callout from '@mdx/Callout.astro';

<Prerequisites>
- Get started with [SQLite](/docs/sqlite/get-started-sqlite)
- [Select statement](/docs/sqlite/select)
- [Filters](/docs/sqlite/operators) and [sql operator](/docs/sqlite/sql)
- [Aggregations](/docs/sqlite/select#aggregations) and [Aggregation helpers](/docs/sqlite/select#aggregations-helpers)
- [Joins](/docs/sqlite/joins)
</Prerequisites>

To count all rows in table you can use `count()` function or `sql` operator like below:

<CodeTabs items={["index.ts", "schema.ts"]}>
  <CodeTab>
    ```ts copy {6,9}
    import { count, sql } from 'drizzle-orm';
    import { products } from './schema';

    const db = drizzle(...);

    await db.select({ count: count() }).from(products);

    // Under the hood, the count() function casts its result to a number at runtime.
    await db.select({ count: sql`count(*)`.mapWith(Number) }).from(products);
    ```

    ```ts
    // result type
    type Result = {
      count: number;
    }[];
    ```

    ```sql
    select count(*) from products;
    ```
  </CodeTab>
  ```ts
  import { integer, sqliteTable, text } from 'drizzle-orm/sqlite-core';

  export const products = sqliteTable('products', {
    id: integer('id').primaryKey({ autoIncrement: true }),
    name: text('name').notNull(),
    discount: integer('discount'),
    price: integer('price').notNull(),
  });
  ```
</CodeTabs>

To count rows where the specified column contains non-NULL values you can use `count()` function with a column:

<Section>
```ts copy {1}
await db.select({ count: count(products.discount) }).from(products);
```

```ts
// result type
type Result = {
  count: number;
}[];
```

```sql
select count("discount") from products;
```
</Section>

In SQLite, `count()` result returns as integer.

<Section>
```ts copy {3,4}
import { sql } from 'drizzle-orm';

await db.select({ count: sql<number>`count(*)` }).from(products);
await db.select({ count: sql<number>`count(${products.discount})` }).from(products);
```

```sql
select count(*) from products;
select count("discount") from products;
```
</Section>

<Callout type="warning">
By specifying `sql<number>`, you are telling Drizzle that the **expected** type of the field is `number`.<br />
If you specify it incorrectly (e.g. use `sql<string>` for a field that will be returned as a number), the runtime value won't match the expected type.
Drizzle cannot perform any type casts based on the provided type generic, because that information is not available at runtime.

If you need to apply runtime transformations to the returned value, you can use the [`.mapWith()`](/docs/sqlite/sql#sqlmapwith) method.
</Callout>

To count rows that match a condition you can use `.where()` method:

<Section>
```ts copy {4,6}
import { count, gt } from 'drizzle-orm';

await db
  .select({ count: count() })
  .from(products)
  .where(gt(products.price, 100));
```

```sql
select count(*) from products where price > 100
```
</Section>

This is how you can use `count()` function with joins and aggregations:

<CodeTabs items={["index.ts", "schema.ts"]}>
	<CodeTab>
    ```ts copy {8,11,12,13}
    import { count, eq } from 'drizzle-orm';
    import { countries, cities } from './schema';

    // Count cities in each country
    await db
      .select({
        country: countries.name,
        citiesCount: count(cities.id),
      })
      .from(countries)
      .leftJoin(cities, eq(countries.id, cities.countryId))
      .groupBy(countries.id)
      .orderBy(countries.name);
    ```

    ```sql
    select countries.name, count("cities"."id") from countries
      left join cities on countries.id = cities.country_id
      group by countries.id
      order by countries.name;
    ```
  </CodeTab>
  ```ts
  import { integer, sqliteTable, text } from 'drizzle-orm/sqlite-core';

  export const countries = sqliteTable('countries', {
    id: integer('id').primaryKey({ autoIncrement: true }),
    name: text('name').notNull(),
  });

  export const cities = sqliteTable('cities', {
    id: integer('id').primaryKey({ autoIncrement: true }),
    name: text('name').notNull(),
    countryId: integer('country_id').notNull().references(() => countries.id),
  });
  ```
</CodeTabs>


Source: https://orm.drizzle.team/docs/sqlite/indexes-constraints

import Callout from '@mdx/Callout.astro';
import Section from '@mdx/Section.astro';

# Indexes & Constraints

## Constraints

SQL constraints are the rules enforced on table columns. They are used to prevent invalid data from being entered into the database.

This ensures the accuracy and reliability of your data in the database.

### Default

The `DEFAULT` clause specifies a default value to use for the column if no value provided by the user when doing an `INSERT`.
If there is no explicit `DEFAULT` clause attached to a column definition,
then the default value of the column is `NULL`.

An explicit `DEFAULT` clause may specify that the default value is `NULL`,
a string constant, a blob constant, a signed-number, or any constant expression enclosed in parentheses.

<Section>
    ```typescript
    import { sql } from "drizzle-orm";
    import { integer, sqliteTable } from "drizzle-orm/sqlite-core";

    const table = sqliteTable('table', {
      int1: integer('int1').default(42),
      int2: integer('int2').default(sql`(abs(42))`)
    });

    ```
    ```sql
    CREATE TABLE `table` (
      `int1` integer DEFAULT 42
      `int2` integer DEFAULT (abs(42))
    );
    ```
    </Section>

### Not null

By default, a column can hold **NULL** values. The `NOT NULL` constraint enforces a column to **NOT** accept **NULL** values.  

This enforces a field to always contain a value, which means that you cannot insert a new record,
or update a record without adding a value to this field.

<Section>
      ```typescript copy
      const table = sqliteTable('table', { 
        numInt: integer('numInt').notNull() 
      });
      ```

      ```sql
      CREATE TABLE table (
        `numInt` integer NOT NULL
      );
      ```
    </Section>

### Unique

The `UNIQUE` constraint ensures that all values in a column are different.  

Both the `UNIQUE` and `PRIMARY KEY` constraints provide a guarantee for uniqueness for a column or set of columns.

A `PRIMARY KEY` constraint automatically has a `UNIQUE` constraint.  

<Callout type="info" emoji="ℹ️">
  You can have many `UNIQUE` constraints per table, but only one `PRIMARY KEY` constraint per table.
</Callout>

<Section>
      ```typescript copy
      import { int, text, unique, sqliteTable } from "drizzle-orm/sqlite-core";

      export const user = sqliteTable('user', {
        id: int('id').unique(),
      });

      export const table = sqliteTable('table', {
        id: int('id').unique('custom_name'),
      });

      export const composite = sqliteTable('composite_example', {
        id: int('id'),
        name: text('name'),
      }, (t) => [
        unique().on(t.id, t.name),
        unique('custom_name').on(t.id, t.name)
      ]);
      ```

      ```sql
	  CREATE TABLE `user` (
        `id` integer UNIQUE
      );

      CREATE TABLE `table` (
        `id` integer CONSTRAINT `custom_name` UNIQUE
      );

      CREATE TABLE `composite_example` (
        `id` integer,
        `name` text,
        CONSTRAINT `composite_example_id_name_unique` UNIQUE(`id`,`name`),
        CONSTRAINT `custom_name` UNIQUE(`id`,`name`)
      );
      ```
    </Section>

### Check

The `CHECK` constraint is used to limit the value range that can be placed in a column.

If you define a `CHECK` constraint on a column it will allow only certain values for this column.  

If you define a `CHECK` constraint on a table it can limit the values in certain columns based on values in other columns in the row.

<Section>
      ```typescript copy
      import { sql } from "drizzle-orm";
      import { check, int, sqliteTable, text } from "drizzle-orm/sqlite-core";

      export const users = sqliteTable(
        "users",
        {
          id: int().primaryKey(),
          username: text().notNull(),
          age: int(),
        },
        (table) => [
          check("age_check1", sql`${table.age} > 21`)
        ]
      );
      ```
      ```sql
      CREATE TABLE `users` (
	      `id` integer PRIMARY KEY NOT NULL,
	      `username` text NOT NULL,
	      `age` integer,
	      CONSTRAINT "age_check1" CHECK("age" > 21)
      );
      ```
    </Section>

### Primary Key

The `PRIMARY KEY` constraint uniquely identifies each record in a table.  
Primary keys must contain `UNIQUE` values, and cannot contain `NULL` values.  

A table can have only **ONE** primary key; and in the table, this primary key can consist of single or multiple columns (fields).

<Section>
      ```typescript copy
      import { integer, sqliteTable } from "drizzle-orm/sqlite-core";

      export const user = sqliteTable("user", {
        id: integer().primaryKey({ autoIncrement: true }),
      })

      export const pet = sqliteTable("pet", {
        id: integer().primaryKey(),
      })
      ```

      ```sql
      CREATE TABLE `user` (
        `id` integer PRIMARY KEY AUTOINCREMENT
      );

      CREATE TABLE `pet` (
        `id` integer PRIMARY KEY
      )
      ```
    </Section>

### Composite Primary Key

Just like `PRIMARY KEY`, composite primary key uniquely identifies each record in a table using multiple fields.

Drizzle ORM provides a standalone `primaryKey` operator for that:

<Section>
      ```typescript copy {18, 19}
      import { integer, text, primaryKey, sqliteTable} from "drizzle-orm/sqlite-core";

      export const user = sqliteTable("user", {
        id: integer().primaryKey({ autoIncrement: true }),
        name: text(),
      });

      export const book = sqliteTable("book", {
        id: integer().primaryKey({ autoIncrement: true }),
        name: text(),
      });

      export const bookToAuthor = sqliteTable("book_to_author", {
        authorId: integer("author_id"),
        bookId: integer("book_id"),
      }, (table) => [
        primaryKey({ columns: [table.bookId, table.authorId] }),
        // Or PK with custom name
        primaryKey({ name: 'custom_name', columns: [table.bookId, table.authorId] })
      ]);
      ```
      ```sql {6}
      ...

      CREATE TABLE `book_to_author` (
        `author_id` integer,
        `book_id` integer,
        PRIMARY KEY(`book_id`, `author_id`)
      );
      ```
    </Section>

### Foreign key

The `FOREIGN KEY` constraint is used to prevent actions that would destroy links between tables.
A `FOREIGN KEY` is a field (or collection of fields) in one table, that refers to the `PRIMARY KEY` in another table.
The table with the foreign key is called the child table, and the table with the primary key is called the referenced or parent table.

Drizzle ORM provides several ways to declare foreign keys.
You can declare them in a column declaration statement:

	```typescript {11}
    import { integer, text, sqliteTable } from "drizzle-orm/sqlite-core";

    export const user = sqliteTable("user", {
      id: integer().primaryKey({ autoIncrement: true }),
      name: text(),
    });

    export const book = sqliteTable("book", {
      id: integer().primaryKey({ autoIncrement: true }),
      name: text(),
      authorId: integer("author_id").references(() => user.id)
    });
    ```

If you want to do a self reference, due to a TypeScript limitations you will have to either explicitly
set return type for reference callback or use a standalone `foreignKey` operator.

	```typescript {6,15-19}
    import { integer, text, foreignKey, sqliteTable, type AnySQLiteColumn } from "drizzle-orm/sqlite-core";

    export const user = sqliteTable("user", {
      id: integer().primaryKey({ autoIncrement: true }),
      name: text(),
      parentId: integer("parent_id").references((): AnySQLiteColumn => user.id)
    });

    //or
    export const user = sqliteTable("user", {
      id: integer().primaryKey({ autoIncrement: true }),
      name: text(),
      parentId: integer(),
    }, (table) => [
      foreignKey({
        columns: [table.parentId],
        foreignColumns: [table.id],
        name: "custom_fk"
      })
    ]);
    ```

To declare multi-column foreign keys you can use a dedicated `foreignKey` operator:

	```typescript {4-5,15-19}
    import { integer, text, primaryKey, foreignKey, sqliteTable } from "drizzle-orm/sqlite-core";

    export const user = sqliteTable("user", {
      firstName: text("firstName"),
      lastName: text("lastName"),
    }, (table) => [
      primaryKey({ columns: [table.firstName, table.lastName]})
    ]);

    export const profile = sqliteTable("profile", {
      id: integer().primaryKey({ autoIncrement: true }),
      userFirstName: text("user_first_name"),
      userLastName: text("user_last_name"),
    }, (table) => [
      foreignKey({
        columns: [table.userFirstName, table.userLastName],
        foreignColumns: [user.firstName, user.lastName],
        name: "custom_name"
      })
    ]);
    ```

## Indexes

Drizzle ORM provides API for both `index` and `unique index` declaration:

<Section>
    ```typescript {8-9}
    import { integer, text, index, uniqueIndex, sqliteTable } from "drizzle-orm/sqlite-core";

    export const user = sqliteTable("user", {
      id: integer().primaryKey({ autoIncrement: true }),
      name: text(),
      email: text(),
    }, (table) => [
      index("name_idx").on(table.name),
      uniqueIndex("email_idx").on(table.email),
    ]);
    ```
    ```sql {5-6}
    CREATE TABLE `user` (
      ...
    );

    CREATE INDEX `name_idx` ON `user` (`name`);
    CREATE UNIQUE INDEX `email_idx` ON `user` (`email`);
    ```
    </Section>

     Drizzle ORM provides set of all params for index creation:
     
    ```typescript
    // Index declaration reference
    index("name")
      .on(table.name)
      .where(sql`...`)
    ```


Source: https://orm.drizzle.team/docs/sqlite/insert

import Section from '@mdx/Section.astro';
import Callout from '@mdx/Callout.astro';
import Tab from '@mdx/Tab.astro';
import Tabs from '@mdx/Tabs.astro';

# SQL Insert

<Callout type='info'>
All the values provided to `.values()`are parameterized automatically.
For example, this query:
```ts
await db.insert(users).values({ id: 1, name: 'Andrew' });
```
will be translated to:
```sql
insert into "users" ("id", "name") values (?, ?) -- params: ['Andrew']
```
</Callout>

<br/>

Drizzle ORM provides you the most SQL-like way to insert rows into the database tables.

Inserting data with Drizzle is extremely straightforward and sql-like. See for yourself:

<Section>
```typescript copy 
await db.insert(users).values({ name: 'Andrew' });
```
```sql
insert into "users" ("name") values ('Andrew');
```
</Section>

If you need insert type for a particular table you can use `typeof usersTable.$inferInsert` syntax. 
```typescript copy 
type NewUser = typeof users.$inferInsert;

const insertUser = async (user: NewUser) => {
  return db.insert(users).values(user);
}

const newUser: NewUser = { name: "Alef" };
await insertUser(newUser);
```

## returning
You can insert a row and get it back in SQLite like such:
```typescript copy
await db.insert(users).values({ name: "Dan" }).returning();

// partial return
await db.insert(users).values({ name: "Partial Dan" }).returning({ insertedId: users.id });
```

## Insert multiple rows
```typescript copy
await db.insert(users).values([{ name: 'Andrew' }, { name: 'Dan' }]);
```

## Upserts and conflicts
Drizzle ORM provides simple interfaces for handling upserts and conflicts.

### On conflict do nothing
`onConflictDoNothing` will cancel the insert if there's a conflict:

```typescript copy
await db.insert(users)
  .values({ id: 1, name: 'John' })
  .onConflictDoNothing();

// explicitly specify conflict target
await db.insert(users)
  .values({ id: 1, name: 'John' })
  .onConflictDoNothing({ target: users.id });
```

### On conflict do update
`onConflictDoUpdate` will update the row if there's a conflict:
```typescript
await db.insert(users)
  .values({ id: 1, name: 'Dan' })
  .onConflictDoUpdate({ target: users.id, set: { name: 'John' } });
```

#### `where` clauses

`on conflict do update` can have a `where` clause in two different places -
as part of the conflict target (i.e. for partial indexes) or as part of the `update` clause:

```sql
insert into "employees" ("employee_id", "name") 
values (123, 'John Doe') 
on conflict ("employee_id") where name <> 'John Doe' 
do update set "name" = excluded.name;

insert into "employees" ("employee_id", "name") 
values (123, 'John Doe') 
on conflict ("employee_id") do update set "name" = 'John Doe' 
where name <> 'John Doe';
```

To specify these conditions in Drizzle, you can use `setWhere` and `targetWhere` clauses:

```typescript
await db.insert(employees)
  .values({ employeeId: 123, name: 'John Doe' })
  .onConflictDoUpdate({
    target: employees.employeeId,
    targetWhere: sql`name <> 'John Doe'`,
    set: { name: sql`excluded.name` }
  });

await db.insert(employees)
  .values({ employeeId: 123, name: 'John Doe' })
  .onConflictDoUpdate({
    target: employees.employeeId,
    set: { name: 'John Doe' },
    setWhere: sql`name <> 'John Doe'`
  });
```

Upsert with composite indexes, or composite primary keys for `onConflictDoUpdate`:

```typescript
await db.insert(users)
  .values({ firstName: 'John', lastName: 'Doe' })
  .onConflictDoUpdate({
    target: [users.firstName, users.lastName],
    set: { firstName: 'John1' }
  });
```

## `with insert` clause

<Callout>
  Check how to use WITH statement with [select](/docs/sqlite/select#with-clause), [update](/docs/sqlite/update#with-update-clause), [delete](/docs/sqlite/delete#with-delete-clause)
</Callout>

Using the `with` clause can help you simplify complex queries by splitting them into smaller subqueries called common table expressions (CTEs):
<Section>
```typescript copy
const userCount = db.$with('user_count').as(
	db.select({ value: sql`count(*)`.as('value') }).from(users)
);

const result = await db.with(userCount)
	.insert(users)
	.values([
		{ username: 'user1', admin: sql`((select * from ${userCount}) = 0)` }
	])
	.returning({
		admin: users.admin
	});
```
```sql
with "user_count" as (select count(*) as "value" from "users")
insert into "users" ("username", "admin")
values ('user1' ((select * from "user_count") = 0))
returning "admin"
```
</Section>

## Insert into ... select

As the SQLite documentation mentions:
<Callout>
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.
</Callout>
<Callout type='warning'>
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.
</Callout>

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


<Tabs items={["Query Builder", "Callback", "SQL template tag"]}>
<Tab>
<Section>
```ts
const insertedEmployees = await db
  .insert(employees)
  .select(
    db.select({ id: users.id, name: users.name }).from(users).where(eq(users.role, 'employee'))
  )
  .returning({
    id: employees.id,
    name: employees.name
  });
```
```ts
const qb = new QueryBuilder();
await db.insert(employees).select(
    qb.select({ id: users.id, name: users.name }).from(users).where(eq(users.role, 'employee'))
);
```
</Section>
</Tab>
<Tab>
<Section>
```ts
await db.insert(employees).select(
    () => db.select({ id: users.id, name: users.name }).from(users).where(eq(users.role, 'employee'))
);
```
```ts
await db.insert(employees).select(
    (qb) => qb.select({ id: users.id, name: users.name }).from(users).where(eq(users.role, 'employee'))
);
```
</Section>
</Tab>
<Tab>
<Section>
```ts
await db.insert(employees).select(
    sql`select "users"."id" as "id", "users"."name" as "name" from "users" where "users"."role" = 'employee'`
);
```
```ts
await db.insert(employees).select(
    () => sql`select "users"."id" as "id", "users"."name" as "name" from "users" where "users"."role" = 'employee'`
);
```
</Section>
</Tab>
</Tabs>


Source: https://orm.drizzle.team/docs/sqlite/joins

import CodeTabs from '@mdx/CodeTabs.astro';
import CodeTab from '@mdx/CodeTab.astro';
import Section from '@mdx/Section.astro';

# Joins [SQL]
Join clause in SQL is used to combine 2 or more tables, based on related columns between them.
Drizzle ORM joins syntax is a balance between the SQL-likeness and type safety.

## Join types
Drizzle ORM has APIs for `INNER JOIN`, `LEFT JOIN`, `RIGHT JOIN`, `FULL JOIN`, and `CROSS JOIN`.
Lets have a quick look at examples based on below table schemas:
```typescript copy
export const users = sqliteTable('users', {
  id: integer().primaryKey({ autoIncrement: true }),
  name: text().notNull(),
});

export const pets = sqliteTable('pets', {
  id: integer().primaryKey({ autoIncrement: true }),
  name: text().notNull(),
  ownerId: integer('owner_id').notNull().references(() => users.id),
})
```

### Left Join
<Section>
```typescript copy
const result = await db.select().from(users).leftJoin(pets, eq(users.id, pets.ownerId))
```
```sql
select ... from "users" left join "pets" on "users"."id" = "pets"."owner_id"
```
```typescript
// result type
const result: {
    user: {
        id: number;
        name: string;
    };
    pets: {
        id: number;
        name: string;
        ownerId: number;
    } | null;
}[];
```
</Section>


### Right Join
<Section>
```typescript copy
const result = await db.select().from(users).rightJoin(pets, eq(users.id, pets.ownerId))
```
```sql
select ... from "users" right join "pets" on "users"."id" = "pets"."owner_id"
```
```typescript
// result type
const result: {
    user: {
        id: number;
        name: string;
    } | null;
    pets: {
        id: number;
        name: string;
        ownerId: number;
    };
}[];
```
</Section>

### Inner Join
<Section>
```typescript copy
const result = await db.select().from(users).innerJoin(pets, eq(users.id, pets.ownerId))
```
```sql
select ... from "users" inner join "pets" on "users"."id" = "pets"."owner_id"
```
```typescript
// result type
const result: {
    user: {
        id: number;
        name: string;
    };
    pets: {
        id: number;
        name: string;
        ownerId: number;
    };
}[];
```
</Section>


### Full Join
<Section>
```typescript copy
const result = await db.select().from(users).fullJoin(pets, eq(users.id, pets.ownerId))
```
```sql
select ... from "users" full join "pets" on "users"."id" = "pets"."owner_id"
```
```typescript
// result type
const result: {
    user: {
        id: number;
        name: string;
    } | null;
    pets: {
        id: number;
        name: string;
        ownerId: number;
    } | null;
}[];
```
</Section>

### Cross Join
<Section>
```typescript copy
const result = await db.select().from(users).crossJoin(pets)
```
```sql
select ... from "users" cross join "pets"
```
```typescript
// result type
const result: {
    user: {
        id: number;
        name: string;
    };
    pets: {
        id: number;
        name: string;
        ownerId: number;
    };
}[];
```
</Section>


## Partial select
If you need to select a particular subset of fields or to have a flat response type, Drizzle ORM
supports joins with partial select and will automatically infer return type based on `.select({ ... })` structure.
<Section>
```typescript copy
await db.select({
  userId: users.id,
  petId: pets.id,
}).from(user).leftJoin(pets, eq(users.id, pets.ownerId))
```
```sql
select "users"."id", "pets"."id" from "users" left join "pets" on "users"."id" = "pets"."owner_id"
```
```typescript
// result type
const result: {
  userId: number;
  petId: number | null;
}[];
```
</Section>
You might've noticed that `petId` can be null now, it's because we're left joining and there can be users without a pet.

It's very important to keep in mind when using `sql` operator for partial selection fields and aggregations when needed,
you should to use `sql<type | null>` for proper result type inference, that one is on you!
<Section>
```typescript copy
const result = await db.select({
  userId: users.id,
  petId: pets.id,
  petName1: sql`upper(${pets.name})`,
  petName2: sql<string | null>`upper(${pets.name})`,
  //˄we should explicitly tell 'string | null' in type, since we're left joining that field
}).from(user).leftJoin(pets, eq(users.id, pets.ownerId))
```
```sql
select "users"."id", "pets"."id", upper("pets"."name")... from "users" left join "pets" on "users"."id" = "pets"."owner_id"
```
```typescript
// result type
const result: {
  userId: number;
  petId: number | null;
  petName1: unknown;
  petName2: string | null;
}[];
```
</Section>
To avoid plethora of nullable fields when joining tables with lots of columns we can utilise our **nested select object syntax**,
our smart type inference will make whole object nullable instead of making all table fields nullable!
<Section>
```typescript copy
await db.select({
  userId: users.id,
  userName: users.name,
  pet: {
    id: pets.id,
    name: pets.name,
    upperName: sql<string>`upper(${pets.name})`
  }
}).from(user).fullJoin(pets, eq(users.id, pets.ownerId))
```
```sql
select ... from "users" full join "pets" on "users"."id" = "pets"."owner_id"
```
```typescript
// result type
const result: {
    userId: number | null;
    userName: string | null;
    pet: {
        id: number;
        name: string;
        upperName: string;
    } | null;
}[];
```
</Section>

## Aliases & Selfjoins
Drizzle ORM supports table aliases which comes really handy when you need to do selfjoins.

Lets say you need to fetch users with their parents:
<CodeTabs items={["index.ts", "schema.ts"]}>
<CodeTab>
```typescript copy
import { user } from "./schema";

const parent = alias(user, "parent");
const result = db
  .select()
  .from(user)
  .leftJoin(parent, eq(parent.id, user.parentId));
```
```sql
select ... from "user" left join "user" "parent" on "parent"."id" = "user"."parent_id"
```
```typescript
// result type
const result: {
    user: {
        id: number;
        name: string;
        parentId: number;
    };
    parent: {
        id: number;
        name: string;
        parentId: number;
    } | null;
}[];
```
</CodeTab>

```typescript
export const user = sqliteTable("user", {
  id: integer().primaryKey({ autoIncrement: true }),
  name: text().notNull(),
  parentId: integer("parent_id").notNull().references((): AnyColumn => user.id)
});
```

</CodeTabs>

## Aggregating results
Drizzle ORM delivers name-mapped results from the driver without changing the structure.

You're free to operate with results the way you want, here's an example of mapping many-one relational data:
```typescript
type User = typeof users.$inferSelect;
type Pet = typeof pets.$inferSelect;

const rows = db.select({
    user: users,
    pet: pets,
  }).from(users).leftJoin(pets, eq(users.id, pets.ownerId)).all();

const result = rows.reduce<Record<number, { user: User; pets: Pet[] }>>(
  (acc, row) => {
    const user = row.user;
    const pet = row.pet;

    if (!acc[user.id]) {
      acc[user.id] = { user, pets: [] };
    }

    if (pet) {
      acc[user.id]!.pets.push(pet);
    }

    return acc;
  },
  {}
);

// result type
const result: Record<number, {
    user: User;
    pets: Pet[];
}>;
```

## Many-to-one example
```typescript
import { sqliteTable, text, integer } from 'drizzle-orm/sqlite-core';
import { drizzle } from 'drizzle-orm/better-sqlite3';

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

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

const db = drizzle();

const result = db.select().from(cities).leftJoin(users, eq(cities.id, users.cityId)).all();
```
## Many-to-many example
```typescript
const users = sqliteTable('users', {
  id: integer().primaryKey(),
  name: text(),
});

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

const usersToChatGroups = sqliteTable('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)
db.select()
  .from(usersToChatGroups)
  .leftJoin(users, eq(usersToChatGroups.userId, users.id))
  .leftJoin(chatGroups, eq(usersToChatGroups.groupId, chatGroups.id))
  .where(eq(chatGroups.id, 1))
  .all();
```


Source: https://orm.drizzle.team/docs/sqlite/kit-custom-migrations

import CodeTab from '@mdx/CodeTab.astro';
import CodeTabs from '@mdx/CodeTabs.astro';
import Section from '@mdx/Section.astro';
import Tab from '@mdx/Tab.astro';
import Tabs from '@mdx/Tabs.astro';
import Callout from '@mdx/Callout.astro';
import Npm from '@mdx/Npm.astro';
import Npx from '@mdx/Npx.astro';
import Steps from '@mdx/Steps.astro';
import Prerequisites from "@mdx/Prerequisites.astro"

# Migrations with Drizzle Kit
<Prerequisites>
- Get started with Drizzle and `drizzle-kit` - [read here](/docs/sqlite/get-started)
- Drizzle schema fundamentals - [read here](/docs/sqlite/sql-schema-declaration)
- Database connection basics - [read here](/docs/sqlite/connect-overview)
- Drizzle migrations fundamentals - [read here](/docs/sqlite/migrations)
- Drizzle Kit [overview](/docs/sqlite/kit-overview) and [config file](/docs/sqlite/drizzle-config-file)
- `drizzle-kit generate` command - [read here](/docs/sqlite/drizzle-kit-generate)
- `drizzle-kit migrate` command - [read here](/docs/sqlite/drizzle-kit-migrate)
</Prerequisites>

Drizzle lets you generate empty migration files to write your own custom SQL migrations 
for DDL alternations currently not supported by Drizzle Kit or data seeding, which you can then run with [`drizzle-kit migrate`](/docs/sqlite/drizzle-kit-migrate) command.

```shell
drizzle-kit generate --custom --name=seed-users
```
<Section>
```plaintext {4}
📦 <project root>
 ├ 📂 drizzle
 │ ├ 📂 20242409125510_init_sql
 │ └ 📂 20242409135510_seed-users
 ├ 📂 src
 └ …
```
```sql
-- ./drizzle/20242409135510_seed-users.sql

INSERT INTO `users` (`name`) VALUES('Dan');
INSERT INTO `users` (`name`) VALUES('Andrew');
INSERT INTO `users` (`name`) VALUES('Dandrew');
```
</Section>

### Running JavaScript and TypeScript migrations
We will add ability to run custom JavaScript and TypeScript migration/seeding scripts in the upcoming release, you can follow [github discussion](https://github.com/drizzle-team/drizzle-orm/discussions/2832).

Source: https://orm.drizzle.team/docs/sqlite/kit-overview

import CodeTab from '@mdx/CodeTab.astro';
import CodeTabs from '@mdx/CodeTabs.astro';
import Section from '@mdx/Section.astro';
import Tab from '@mdx/Tab.astro';
import Tabs from '@mdx/Tabs.astro';
import Callout from '@mdx/Callout.astro';
import Npm from '@mdx/Npm.astro';
import Npx from '@mdx/Npx.astro';
import Steps from '@mdx/Steps.astro';
import Prerequisites from "@mdx/Prerequisites.astro"

# Migrations with Drizzle Kit
<Prerequisites>
- Get started with Drizzle and `drizzle-kit` - [read here](/docs/sqlite/get-started)
- Drizzle schema fundamentals - [read here](/docs/sqlite/sql-schema-declaration)
- Database connection basics - [read here](/docs/sqlite/connect-overview)
- Drizzle migrations fundamentals - [read here](/docs/sqlite/migrations)
</Prerequisites>


**Drizzle Kit** is a CLI tool for managing SQL database migrations with Drizzle.
<Npm>
  -D drizzle-kit
</Npm>
<Callout type="warning">
Make sure to first go through Drizzle [get started](/docs/sqlite/get-started) and [migration fundamentals](/docs/sqlite/migrations) and pick SQL migration flow that suits your business needs best. 
</Callout>

Based on your schema, Drizzle Kit let's you generate and run SQL migration files, 
push schema directly to the database, pull schema from database, spin up drizzle studio and has a couple of utility commands.
<Npx>
drizzle-kit generate
drizzle-kit migrate
drizzle-kit push
drizzle-kit pull
drizzle-kit check
drizzle-kit up
drizzle-kit studio
drizzle-kit export
</Npx>


|                                                      |                                                                                                                                                                    |
| :--------------------------------------------------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| [`drizzle-kit generate`](/docs/sqlite/drizzle-kit-generate) | lets you generate SQL migration files based on your Drizzle schema either upon declaration or on subsequent changes, [see here](/docs/sqlite/drizzle-kit-generate).       |
| [`drizzle-kit migrate`](/docs/sqlite/drizzle-kit-migrate)   | lets you apply generated SQL migration files to your database, [see here](/docs/sqlite/drizzle-kit-migrate).                                                              |
| [`drizzle-kit pull`](/docs/sqlite/drizzle-kit-pull)         | lets you pull(introspect) database schema, convert it to Drizzle schema and save it to your codebase, [see here](/docs/sqlite/drizzle-kit-pull)                           |
| [`drizzle-kit push`](/docs/sqlite/drizzle-kit-push)         | lets you push your Drizzle schema to database either upon declaration or on subsequent schema changes, [see here](/docs/sqlite/drizzle-kit-push)                          |
| [`drizzle-kit studio`](/docs/sqlite/drizzle-kit-studio)     | will connect to your database and spin up proxy server for Drizzle Studio which you can use for convenient database browsing, [see here](/docs/sqlite/drizzle-kit-studio) |
| [`drizzle-kit check`](/docs/sqlite/drizzle-kit-check)       | will walk through all generate migrations and check for any race conditions(collisions) of generated migrations, [see here](/docs/sqlite/drizzle-kit-check)               |
| [`drizzle-kit up`](/docs/sqlite/drizzle-kit-up)             | used to upgrade snapshots of previously generated migrations, [see here](/docs/sqlite/drizzle-kit-up)                                                                     |
| [`drizzle-kit export`](/docs/sqlite/drizzle-kit-export)     | used to convert a TypeScript schema into raw SQL DDL and print it out [see here](/docs/sqlite/drizzle-kit-export)                                                                     |
<br/>

Drizzle Kit is configured through [drizzle.config.ts](/docs/sqlite/drizzle-config-file) configuration file or via CLI params.<br/>
It's required to at least provide SQL `dialect` and `schema` path for Drizzle Kit to know how to generate migrations.
```
📦 <project root>
 ├ 📂 drizzle
 ├ 📂 src
 ├ 📜 .env
 ├ 📜 drizzle.config.ts  <--- Drizzle config file
 ├ 📜 package.json
 └ 📜 tsconfig.json
```

<CodeTabs items={["simple config", "extended config"]}>
```ts
import { defineConfig } from "drizzle-kit";

export default defineConfig({
  dialect: "sqlite",
  schema: "./src/schema.ts",
});
```
```ts
import { defineConfig } from "drizzle-kit";

export default defineConfig({
  out: "./drizzle",
  dialect: "sqlite",
  schema: "./src/schema.ts",

  driver: "d1-http",
  dbCredentials: {
    url: "./database/",
  },

  tablesFilter: "*",

  introspect: {
    casing: "camel",
  },

  migrations: {
    table: "__drizzle_migrations__",
  },

  breakpoints: true,
  verbose: true,
});
```
</CodeTabs>

You can provide Drizzle Kit config path via CLI param, it's very useful when you have multiple database stages or multiple databases or different databases on the same project:

<Npx>
  drizzle-kit push --config=drizzle-dev.drizzle.config
  drizzle-kit push --config=drizzle-prod.drizzle.config
</Npx>
```plaintext {5-6}
📦 <project root>
 ├ 📂 drizzle
 ├ 📂 src
 ├ 📜 .env
 ├ 📜 drizzle-dev.config.ts
 ├ 📜 drizzle-prod.config.ts
 ├ 📜 package.json
 └ 📜 tsconfig.json
```


Source: https://orm.drizzle.team/docs/sqlite/migrations

import Callout from '@mdx/Callout.astro';
import Steps from '@mdx/Steps.astro';
import CodeTab from '@mdx/CodeTab.astro';
import CodeTabs from '@mdx/CodeTabs.astro';
import Section from '@mdx/Section.astro';
import Tab from '@mdx/Tab.astro';
import Tabs from '@mdx/Tabs.astro';
import Npm from '@mdx/Npm.astro';
import Tag from '@mdx/Tag.astro'


# Drizzle migrations fundamentals

SQL databases require you to specify a **strict schema** of entities you're going to store upfront 
and if (when) you need to change the shape of those entities - you will need to do it via **schema migrations**.

There're multiple production grade ways of managing database migrations. 
Drizzle is designed to perfectly suits all of them, regardless of you going **database first** or **codebase first**.

**Database first** is when your database schema is a source of truth. You manage your database schema either directly on the database or 
via database migration tools and then you pull your database schema to your codebase application level entities.  
 
**Codebase first** is when database schema in your codebase is a source of truth and is under version control. You declare and manage your database schema in JavaScript/TypeScript
and then you apply that schema to the database itself either with Drizzle, directly or via external migration tools. 

#### How can Drizzle help?
We've built [**drizzle-kit**](/docs/sqlite/kit-overview) - CLI app for managing migrations with Drizzle. 
```shell
drizzle-kit migrate
drizzle-kit generate
drizzle-kit push
drizzle-kit pull
drizzle-kit export
```
It is designed to let you choose how to approach migrations based on your current business demands. 

It fits in both database and codebase first approaches, it lets you **push your schema** or **generate SQL migration** files or **pull the schema** from database. 
It is perfect wether you work alone or in a team.
<br/>

<hr/>
<rem/>

**Now let's pick the best option for your project:**
<rem/>

<Tag style="font-size: 12px">**Option 1**</Tag>
> I manage database schema myself using external migration tools or by running SQL migrations directly on my database.
> From Drizzle I just need to get current state of the schema from my database and save it as TypeScript schema file.

<Callout collapsed="Expand details">
That's a **database first** approach. You have your database schema as a **source of truth** and 
Drizzle lets you pull database schema to TypeScript using [`drizzle-kit pull`](/docs/sqlite/drizzle-kit-pull) command.

<Section>
```
                                  ┌────────────────────────┐      ┌───────────────────────────────────────┐ 
                                  │                        │ <---  CREATE TABLE `users` (
┌──────────────────────────┐      │                        │        `id` integer primary key autoincrement,
│ ~ drizzle-kit pull       │      │                        │        `name` TEXT,
└─┬────────────────────────┘      │        DATABASE        │        `email` TEXT UNIQUE
  │                               │                        │       );
  └ Pull datatabase schema -----> │                        │
  ┌ Generate Drizzle       <----- │                        │
  │ schema TypeScript file        └────────────────────────┘
  │
  v
```
```typescript
import * as p from "drizzle-orm/sqlite-core";

export const users = p.sqliteTable("users", {
	id: p.integer().primaryKey({ autoIncrement: true }),
	name: p.text(),
	email: p.text().unique(),
});
```
</Section>
</Callout>

<rem/>
<rem/>
<rem/>

<Tag style="font-size: 12px">**Option 2**</Tag>
> I want to have database schema in my TypeScript codebase, 
> I don't wanna deal with SQL migration files.  
> I want Drizzle to "push" my schema directly to the database

<Callout collapsed="Expand details">
That's a **codebase first** approach. You have your TypeScript Drizzle schema as a **source of truth** and 
Drizzle lets you push schema changes to the database using [`drizzle-kit push`](/docs/sqlite/drizzle-kit-push) command.

That's the best approach for rapid prototyping and we've seen dozens of teams 
and solo developers successfully using it as a primary migrations flow in their production applications.

<Section>
```typescript {6} filename="src/schema.ts"
import * as p from "drizzle-orm/sqlite-core";

export const users = p.sqliteTable("users", {
  id: p.integer().primaryKey({ autoIncrement: true }),
  name: p.text(),
  email: p.text(), // <--- added column
});
```
```
Add column to `users` table                                                                          
┌──────────────────────────┐                  
│ + email: text()          │                  
└─┬────────────────────────┘                  
  │                                           
  v                                           
┌──────────────────────────┐                  
│ ~ drizzle-kit push       │                  
└─┬────────────────────────┘                  
  │                                           ┌──────────────────────────┐
  └ Pull current datatabase schema ---------> │                          │
                                              │                          │
  ┌ Generate alternations based on diff <---- │         DATABASE         │
  │                                           │                          │
  └ Apply migrations to the database -------> │                          │
                                       │      └──────────────────────────┘
                                       │
  ┌────────────────────────────────────┴─┐
   ALTER TABLE `users` ADD `email` text; 
```
</Section>
</Callout>

<rem/>
<rem/>
<rem/>

<Tag style="font-size: 12px">**Option 3**</Tag>
> I want to have database schema in my TypeScript codebase, 
> I want Drizzle to generate SQL migration files for me and apply them to my database

<Callout collapsed="Expand details">
That's a **codebase first** approach. You have your TypeScript Drizzle schema as a source of truth and 
Drizzle lets you generate SQL migration files based on your schema changes with [`drizzle-kit generate`](/docs/sqlite/drizzle-kit-generate)
and then apply them to the database with [`drizzle-kit migrate`](/docs/sqlite/drizzle-kit-migrate) commands. 
<Section>
```typescript filename="src/schema.ts"
import * as p from "drizzle-orm/sqlite-core";

export const users = p.sqliteTable("users", {
  id: p.integer().primaryKey({ autoIncrement: true }),
  name: p.text(),
  email: p.text().unique(),
});
```
```                                  
┌────────────────────────┐                  
│ $ drizzle-kit generate │                  
└─┬──────────────────────┘                  
  │                                           
  └ 1. read previous migration folders
    2. find diff between current and previous schema
    3. prompt developer for renames if necessary
  ┌ 4. generate SQL migration and persist to file
  │    ┌─┴───────────────────────────────────────┐  
  │      📂 drizzle       
  │      └ 📂 20242409125510_premium_mister_fear
  │        ├ 📜 snapshot.json
  │        └ 📜 migration.sql
  v
```
```sql
-- drizzle/20242409125510_premium_mister_fear/migration.sql

CREATE TABLE `users` (
	`id` integer PRIMARY KEY AUTOINCREMENT,
	`name` text,
	`email` text UNIQUE
);
```
```
┌───────────────────────┐                  
│ $ drizzle-kit migrate │                  
└─┬─────────────────────┘                  
  │                                                         ┌──────────────────────────┐                                         
  └ 1. read migration.sql files in migrations folder        │                          │
    2. fetch migration history from database -------------> │                          │
  ┌ 3. pick previously unapplied migrations <-------------- │         DATABASE         │
  └ 4. apply new migration to the database ---------------> │                          │
                                                            │                          │
                                                            └──────────────────────────┘
[✓] done!                                                 
```
</Section>
</Callout>

<rem/>
<rem/>
<rem/>

<Tag style="font-size: 12px">**Option 4**</Tag>
> I want to have database schema in my TypeScript codebase,
> I want Drizzle to generate SQL migration files for me and I want Drizzle to apply them during runtime

<Callout collapsed="Expand details">
That's a **codebase first** approach. You have your TypeScript Drizzle schema as a source of truth and 
Drizzle lets you generate SQL migration files based on your schema changes with [`drizzle-kit generate`](/docs/sqlite/drizzle-kit-generate) and then 
you can apply them to the database during runtime of your application.

This approach is widely used for **monolithic** applications when you apply database migrations 
during zero downtime deployment and rollback DDL changes if something fails. 
This is also used in **serverless** deployments with migrations running in **custom resource** once during deployment process.

<Section>
```typescript filename="src/schema.ts"
import * as p from "drizzle-orm/sqlite-core";

export const users = p.sqliteTable("users", {
  id: p.integer().primaryKey({ autoIncrement: true }),
  name: p.text(),
  email: p.text().unique(),
});
```
```                                  
┌────────────────────────┐                  
│ $ drizzle-kit generate │                  
└─┬──────────────────────┘                  
  │                                           
  └ 1. read previous migration folders
    2. find diff between current and previous schema
    3. prompt developer for renames if necessary
  ┌ 4. generate SQL migration and persist to file
  │    ┌─┴───────────────────────────────────────┐  
  │      📂 drizzle       
  │      └ 📂 20242409125510_premium_mister_fear
  │        ├ 📜 snapshot.json
  │        └ 📜 migration.sql
  v
```
```sql
-- drizzle/20242409125510_premium_mister_fear/migration.sql

CREATE TABLE `users` (
	`id` integer PRIMARY KEY AUTOINCREMENT,
	`name` text,
	`email` text UNIQUE
);
```
```ts
// index.ts
import { drizzle } from "drizzle-orm/better-sqlite3"
import { migrate } from 'drizzle-orm/better-sqlite3/migrator';

const db = drizzle(process.env.DATABASE_URL);

await migrate(db);
```
```
┌───────────────────────┐                  
│ npx tsx src/index.ts  │                  
└─┬─────────────────────┘                  
  │                                                      
  ├ 1. init database connection                             ┌──────────────────────────┐                                         
  └ 2. read migration.sql files in migrations folder        │                          │
    3. fetch migration history from database -------------> │                          │
  ┌ 4. pick previously unapplied migrations <-------------- │         DATABASE         │
  └ 5. apply new migration to the database ---------------> │                          │
                                                            │                          │
                                                            └──────────────────────────┘
[✓] done!                                                 
```
</Section>
</Callout>

<rem/>
<rem/>
<rem/>

<Tag style="font-size: 12px">**Option 5**</Tag>
> I want to have database schema in my TypeScript codebase,
> I want Drizzle to generate SQL migration files for me,
> but I will apply them to my database myself or via external migration tools 

<Callout collapsed="Expand details">
That's a **codebase first** approach. You have your TypeScript Drizzle schema as a source of truth and 
Drizzle lets you generate SQL migration files based on your schema changes with [`drizzle-kit generate`](/docs/sqlite/drizzle-kit-generate) and then 
you can apply them to the database either directly or via external migration tools.

<Section>
```typescript filename="src/schema.ts"
import * as p from "drizzle-orm/sqlite-core";

export const users = p.sqliteTable("users", {
  id: p.integer().primaryKey({ autoIncrement: true }),
  name: p.text(),
  email: p.text().unique(),
});
```
```                                  
┌────────────────────────┐                  
│ $ drizzle-kit generate │                  
└─┬──────────────────────┘                  
  │                                           
  └ 1. read previous migration folders
    2. find diff between current and previous scheama
    3. prompt developer for renames if necessary
  ┌ 4. generate SQL migration and persist to file
  │    ┌─┴───────────────────────────────────────┐  
  │      📂 drizzle       
  │      └ 📂 20242409125510_premium_mister_fear
  │        ├ 📜 snapshot.json
  │        └ 📜 migration.sql
  v
```
```sql
-- drizzle/20242409125510_premium_mister_fear/migration.sql

CREATE TABLE `users` (
	`id` integer PRIMARY KEY AUTOINCREMENT,
	`name` text,
	`email` text UNIQUE
);
```
```
┌───────────────────────────────────┐                  
│ (._.) now you run your migrations │           
└─┬─────────────────────────────────┘  
  │
 directly to the database
  │                                         ┌────────────────────┐
  ├────────────────────────────────────┬───>│                    │  
  │                                    │    │      Database      │           
 or via external tools                 │    │                    │   
  │                                    │    └────────────────────┘
  │  ┌────────────────────┐            │      
  └──│ Bytebase           ├────────────┘         
     ├────────────────────┤  
     │ Liquibase          │
     ├────────────────────┤ 
     │ Atlas              │
     ├────────────────────┤ 
     │ etc…               │
     └────────────────────┘

[✓] done!                                                 
```
</Section>
</Callout>

<rem/>
<rem/>
<rem/>

<Tag style="font-size: 12px">**Option 6**</Tag>
> I want to have database schema in my TypeScript codebase,
> I want Drizzle to output the SQL representation of my Drizzle schema to the console,
> and I will apply them to my database via [Atlas](https://atlasgo.io/guides/orms/drizzle)

<Callout collapsed="Expand details">
That's a **codebase first** approach. You have your TypeScript Drizzle schema as a source of truth and 
Drizzle lets you export SQL statements based on your schema changes with [`drizzle-kit export`](/docs/sqlite/drizzle-kit-generate) and then 
you can apply them to the database via [Atlas](https://atlasgo.io/guides/orms/drizzle) or other external SQL migration tools.

<Section>
```typescript filename="src/schema.ts"
import * as p from "drizzle-orm/sqlite-core";

export const users = p.sqliteTable("users", {
  id: p.integer().primaryKey({ autoIncrement: true }),
  name: p.text(),
  email: p.text().unique(),
});
```
```                                  
┌────────────────────────┐                  
│ $ drizzle-kit export   │                  
└─┬──────────────────────┘                  
  │                                           
  └ 1. read your drizzle schema
    2. generated SQL representation of your schema
  ┌ 3. outputs to console
  │    
  │        
  v
```
```sql
CREATE TABLE `users` (
        `id` integer PRIMARY KEY AUTOINCREMENT,
        `name` text,
        `email` text UNIQUE
);
```
```
┌───────────────────────────────────┐                  
│ (._.) now you run your migrations │           
└─┬─────────────────────────────────┘  
  │
 via Atlas
  │                                    ┌──────────────┐
  │  ┌────────────────────┐            │              │
  └──│ Atlas              ├───────────>│  Database    │      
     └────────────────────┘            │              │       
                                       └──────────────┘

[✓] done!                                                 
```
</Section>
</Callout>

<rem/>
<rem/>


Source: https://orm.drizzle.team/docs/sqlite/operators

import Section from '@mdx/Section.astro';

# Filter and conditional operators
We natively support all dialect specific filter and conditional operators.

You can import all filter & conditional from `drizzle-orm`:
```typescript copy
import { eq, ne, gt, gte, ... } from "drizzle-orm";
```

### eq

  
Value equal to `n`
<Section>
```typescript copy
import { eq } from "drizzle-orm";

db.select().from(table).where(eq(table.column, 5));
```

```sql copy
SELECT * FROM table WHERE table.column = 5
```
</Section>

<Section>
```typescript
import { eq } from "drizzle-orm";

db.select().from(table).where(eq(table.column1, table.column2));
```

```sql
SELECT * FROM table WHERE table.column1 = table.column2
```
</Section>

### ne

  
Value is not equal to `n`  
<Section>
```typescript
import { ne } from "drizzle-orm";

db.select().from(table).where(ne(table.column, 5));
```

```sql
SELECT * FROM table WHERE table.column <> 5
```
</Section>

<Section>
```typescript
import { ne } from "drizzle-orm";

db.select().from(table).where(ne(table.column1, table.column2));
```

```sql
SELECT * FROM table WHERE table.column1 <> table.column2
```
</Section>

## ---

### gt
 
  
Value is greater than `n`
<Section>
```typescript
import { gt } from "drizzle-orm";

db.select().from(table).where(gt(table.column, 5));
```

```sql
SELECT * FROM table WHERE table.column > 5
```
</Section>

<Section>
```typescript
import { gt } from "drizzle-orm";

db.select().from(table).where(gt(table.column1, table.column2));
```

```sql
SELECT * FROM table WHERE table.column1 > table.column2
```
</Section>

### gte

  
Value is greater than or equal to `n`
<Section>
```typescript
import { gte } from "drizzle-orm";

db.select().from(table).where(gte(table.column, 5));
```

```sql
SELECT * FROM table WHERE table.column >= 5
```
</Section>

<Section>
```typescript
import { gte } from "drizzle-orm";

db.select().from(table).where(gte(table.column1, table.column2));
```

```sql
SELECT * FROM table WHERE table.column1 >= table.column2
```
</Section>

### lt

  
Value is less than `n`
<Section>
```typescript
import { lt } from "drizzle-orm";

db.select().from(table).where(lt(table.column, 5));
```

```sql
SELECT * FROM table WHERE table.column < 5
```
</Section>

<Section>
```typescript
import { lt } from "drizzle-orm";

db.select().from(table).where(lt(table.column1, table.column2));
```

```sql
SELECT * FROM table WHERE table.column1 < table.column2
```
</Section>

### lte

  
Value is less than or equal to `n`.

<Section>
```typescript
import { lte } from "drizzle-orm";

db.select().from(table).where(lte(table.column, 5));
```

```sql
SELECT * FROM table WHERE table.column <= 5
```
</Section>

<Section>
```typescript
import { lte } from "drizzle-orm";

db.select().from(table).where(lte(table.column1, table.column2));
```

```sql
SELECT * FROM table WHERE table.column1 <= table.column2
```
</Section>

## ---

### exists

  
Value exists
<Section>
```typescript
import { exists } from "drizzle-orm";

const query = db.select().from(table2)
db.select().from(table).where(exists(query));
```

```sql
SELECT * FROM table WHERE EXISTS (SELECT * from table2)
```
</Section>

### notExists

<Section>
```typescript
import { notExists } from "drizzle-orm";

const query = db.select().from(table2)
db.select().from(table).where(notExists(query));
```

```sql
SELECT * FROM table WHERE NOT EXISTS (SELECT * from table2)
```
</Section>

### isNull

  
Value is `null`
<Section>
```typescript
import { isNull } from "drizzle-orm";

db.select().from(table).where(isNull(table.column));
```

```sql
SELECT * FROM table WHERE table.column IS NULL
```
</Section>

### isNotNull

  
Value is not `null`
<Section>
```typescript
import { isNotNull } from "drizzle-orm";

db.select().from(table).where(isNotNull(table.column));
```

```sql
SELECT * FROM table WHERE table.column IS NOT NULL
```
</Section>

## ---

### inArray

  
Value is in array of values
<Section>
```typescript
import { inArray } from "drizzle-orm";

db.select().from(table).where(inArray(table.column, [1, 2, 3, 4]));
```

```sql
SELECT * FROM table WHERE table.column in (1, 2, 3, 4)
```
</Section>

<Section>
```typescript
import { inArray } from "drizzle-orm";

const query = db.select({ data: table2.column }).from(table2);
db.select().from(table).where(inArray(table.column, query));
```

```sql
SELECT * FROM table WHERE table.column IN (SELECT table2.column FROM table2)
```
</Section>

### notInArray

  
Value is not in array of values
<Section>
```typescript
import { notInArray } from "drizzle-orm";

db.select().from(table).where(notInArray(table.column, [1, 2, 3, 4]));
```

```sql
SELECT * FROM table WHERE table.column NOT in (1, 2, 3, 4)
```
</Section>

<Section>
```typescript
import { notInArray } from "drizzle-orm";

const query = db.select({ data: table2.column }).from(table2);
db.select().from(table).where(notInArray(table.column, query));
```

```sql
SELECT * FROM table WHERE table.column NOT IN (SELECT table2.column FROM table2)
```
</Section>

## ---

### between

  
Value is between two values
<Section>
```typescript
import { between } from "drizzle-orm";

db.select().from(table).where(between(table.column, 2, 7));
```

```sql
SELECT * FROM table WHERE table.column BETWEEN 2 AND 7
```
</Section>

### notBetween

  
Value is not between two value
<Section>
```typescript
import { notBetween } from "drizzle-orm";

db.select().from(table).where(notBetween(table.column, 2, 7));
```

```sql
SELECT * FROM table WHERE table.column NOT BETWEEN 2 AND 7
```
</Section>

## ---

### like

  
Value is like other value, case sensitive
<Section>
```typescript
import { like } from "drizzle-orm";

db.select().from(table).where(like(table.column, "%llo wor%"));
```

```sql
SELECT * FROM table  WHERE table.column LIKE '%llo wor%'
```
</Section>

### notLike

  
Value is not like some other value, case sensitive
<Section>
```typescript
import { notLike } from "drizzle-orm";

db.select().from(table).where(notLike(table.column, "%llo wor%"));
```

```sql
SELECT * FROM table WHERE table.column NOT LIKE '%llo wor%'
```
</Section>

## ---

### not

  
All conditions must return `false`.

<Section>
```typescript
import { eq, not } from "drizzle-orm";

db.select().from(table).where(not(eq(table.column, 5)));
```

```sql
SELECT * FROM table WHERE NOT (table.column = 5)
```
</Section>

### and

  
All conditions must return `true`.

<Section>
```typescript
import { gt, lt, and } from "drizzle-orm";

db.select().from(table).where(and(gt(table.column, 5), lt(table.column, 7)));
```

```sql
SELECT * FROM table WHERE (table.column > 5 AND table.column < 7)
```
</Section>

### or

  
One or more conditions must return `true`.

<Section>
```typescript
import { gt, lt, or } from "drizzle-orm";

db.select().from(table).where(or(gt(table.column, 5), lt(table.column, 7)));
```

```sql
SELECT * FROM table WHERE (table.column > 5 OR table.column < 7)
```
</Section>

## ---


Source: https://orm.drizzle.team/docs/sqlite/overview

import Callout from '@mdx/Callout.astro';
import CodeTabs from '@mdx/CodeTabs.astro';
import YoutubeCards from '@mdx/YoutubeCards.astro';
import GetStartedLinks from '@mdx/GetStartedLinks/index.astro'

# Drizzle ORM

Drizzle ORM is a headless TypeScript ORM with a head. 🐲
> Drizzle is a good friend who's there for you when necessary and doesn't bother when you need some space.

It looks and feels simple, performs on day _1000_ of your project,\
lets you do things your way, and is there when you need it.

**It's the only ORM with both [relational](/docs/sqlite/rqb) and [SQL-like](/docs/sqlite/select) query APIs**, 
providing you the best of both worlds when it comes to accessing your relational data. 
Drizzle is lightweight, performant, typesafe, non-lactose, gluten-free, sober, flexible and **serverless-ready by design**.
Drizzle is not just a library, it's an experience. 🤩

[![Drizzle bestofjs](@/assets/images/bestofjs.jpg)](https://bestofjs.org/projects/drizzle-orm)

## Headless ORM? 
First and foremost, Drizzle is a library and a collection of complementary opt-in tools. 

**ORM** stands for _object relational mapping_, and developers tend to call Django-like or Spring-like tools an ORM. 
We truly believe it's a misconception based on legacy nomenclature, and we call them **data frameworks**.

<Callout type="error" emoji="️💔">
  With data frameworks you have to build projects **around them** and not **with them**.
</Callout>

**Drizzle** lets you build your project the way you want, without interfering with your project or structure. 

Using Drizzle you can define and manage database schemas in TypeScript, access your data in a SQL-like 
or relational way, and take advantage of opt-in tools 
to push your developer experience _through the roof_. 🤯 

## Why SQL-like?
**If you know SQL, you know Drizzle.**

Other ORMs and data frameworks tend to deviate/abstract you away from SQL, which 
leads to a double learning curve: needing to know both SQL and the framework's API.  

Drizzle is the opposite. 
We embrace SQL and built Drizzle to be SQL-like at its core, so you can have zero to no 
learning curve and access to the full power of SQL.  

We bring all the familiar **[SQL schema](/docs/sqlite/sql-schema-declaration)**, **[queries](/docs/sqlite/select)**, 
**[automatic migrations](/docs/sqlite/migrations)** and **[one more thing](/docs/sqlite/rqb)**. ✨

<CodeTabs items={["index.ts", "schema.ts", "migration.sql"]}>
```typescript copy
// Access your data
await db
	.select()
	.from(countries)
	.leftJoin(cities, eq(cities.countryId, countries.id))
	.where(eq(countries.id, 10))
```
```typescript copy
// manage your schema
export const countries = sqliteTable('countries', {
  id: integer().primaryKey({ autoIncrement: true }),
  name: text(),
});

export const cities = sqliteTable('cities', {
  id: integer().primaryKey({ autoIncrement: true }),
  name: text(),
  countryId: integer('country_id').references(() => countries.id),
});
```
```sql
-- generate migrations
CREATE TABLE `countries` (
	`id` integer PRIMARY KEY AUTOINCREMENT,
	`name` text
);

CREATE TABLE `cities` (
	`id` integer PRIMARY KEY AUTOINCREMENT,
	`name` text,
	`country_id` integer,
	CONSTRAINT `fk_cities_country_id_countries_id_fk` FOREIGN KEY (`country_id`) REFERENCES `countries`(`id`)
);
```
</CodeTabs>

## Why not SQL-like?
We're always striving for a perfectly balanced solution, and while SQL-like does cover 100% of the needs, 
there are certain common scenarios where you can query data in a better way.  

We've built the **[Queries API](/docs/sqlite/rqb)** for you, so you can fetch relational nested data from the database 
in the most convenient and performant way, and never think about joins and data mapping.  

**Drizzle always outputs exactly 1 SQL query.** Feel free to use it with serverless databases and never worry about performance or roundtrip costs!

```ts
const result = await db.query.users.findMany({
	with: {
		posts: true
	},
});
```

## Serverless?
<Callout type="info" emoji="🥳">
  The best part is no part. **Drizzle has exactly 0 dependencies!**
</Callout>


![Drizzle is slim an Serverless ready](@/assets/images/drizzle31kb.jpg)
  
Drizzle ORM is dialect-specific, slim, performant and serverless-ready **by design**.  

We've spent a lot of time to make sure you have best-in-class SQL dialect support, including Postgres, MySQL, and others.

Drizzle operates natively through industry-standard database drivers. We support all major **[PostgreSQL](/docs/get-started-postgresql)**, **[MySQL](/docs/mysql/get-started-mysql)**, **[SQLite](/docs/sqlite/get-started-sqlite)**, **[SingleStore](/docs/singlestore/get-started-singlestore)**, **[MSSQL](/docs/mssql/get-started-mssql)** or **[CockroachDB](/docs/cockroach/get-started-cockroach)** drivers out there, and we're adding new ones **[really fast](https://twitter.com/DrizzleORM/status/1653082492742647811?s=20)**.  


## Welcome on board!
More and more companies are adopting Drizzle in production, experiencing immense benefits in both DX and performance.

**We're always there to help, so don't hesitate to reach out. We'll gladly assist you in your Drizzle journey!**

We have an outstanding **[Discord community](https://driz.link/discord)** and welcome all builders to our **[Twitter](https://twitter.com/drizzleorm)**.
  
Now go build something awesome with Drizzle and your **[PostgreSQL](/docs/get-started-postgresql)**, **[MySQL](/docs/mysql/get-started-mysql)**, **[SQLite](/docs/sqlite/get-started-sqlite)**, **[MSSQL](/docs/mssql/get-started-mssql)** or **[CockroachDB](/docs/cockroach/get-started-cockroach)** database. 🚀

### Video Showcase

{/* tRPC + NextJS App Router = Simple Typesafe APIs
Jack Herrington 19:17
https://www.youtube.com/watch?v=qCLV0Iaq9zU */}
{/* https://www.youtube.com/watch?v=qDunJ0wVIec */}
{/* https://www.youtube.com/watch?v=NZpPMlSAez0 */}

 {/* https://www.youtube.com/watch?v=-A0kMiJqQRY */}

<YoutubeCards cards={[
	{
		id: "vyU5mJGCJMw",
		title: "Full Drizzle Course for Beginners",
		description: "Code Genix",
		time: "1:37:39",
	},
	{
		id: "7-NZ0MlPpJA",
		title: "Learn Drizzle In 60 Minutes",
		description: "Web Dev Simplified",
		time: "56:09"
	},
	{
		id: "i_mAHOhpBSA",
		title: "Drizzle ORM in 100 Seconds",
		description: "Fireship",
		time: "2:55"
	},
	{
		id: "hIYNOiZXQ7Y",
		title: "Learn Drizzle ORM in 13 mins (crash course)",
		description: "Neon",
		time: "14:00"
	},
	{
		id: "4ZhtoOFKFP8",
		title: "Easiest Database Setup in Next.js&nbsp;14 with Turso&nbsp;&&nbsp;Drizzle",
		description: "Sam Meech-Ward",
		time: '38:08'
	}, 
	{
		id: "NfVELsEZFsA",
		title: "Next.js Project with Vercel, Neon, Drizzle, TailwindCSS, FlowBite and more!",
		description: "CodingEntrepreneurs",
		time: '5:46:28'
	}, 
	{
		id: "_SLxGYzv6jo",
		title: "I Have A New Favorite Database&nbsp;Tool",
		description: "Theo - t3.gg",
		time: '5:46'
	}, 
	{
		id: "Qo-RXkSwOtc",
		title: "Drizzle ORM First impressions - migrations, relations, queries!",
		description: "Marius Espejo",
		time: '33:52'
	},
	{
		id: "yXNEqyvA0OY",
		title: "I want to learn Drizzle ORM, so I'm starting another next14 project",
		description: "Web Dev Cody",
		time: "9:00"
	},
	{
		id: "h7vVhR-dFYo",
		title: "Picking an ORM is Getting Harder...",
		description: "Ben Davis",
		time: "5:18"
	},
	{
		id: "8met6WTk0mQ",
		title: "This New Database Tool is a Game-Changer",
		description: "Josh tried coding",
		time: "8:49"
	},
	{
		id: "woWW1T9DXEY",
		title: "My Favorite Database Tool Just Got EVEN Better",
		description: "Josh tried coding",
		time: "4:23"
	},
	{
		id: "A3l6YYkXzzg",
		title: "SaaS Notion Clone with Realtime cursors, Nextjs 13, Stripe, Drizzle ORM, Tailwind, Supabase, Sockets",
		description: "Web Prodigies",
		time: "11:41:46"
	},
	{
		id: "EQfaw5bDE1s",
		title: "SvelteKit + Drizzle Code Breakdown",
		description: "Ben Davis",
		time: "12:18"
	},
	{
		id: "b6VhN_HHDiQ",
		title: "Build a Multi-Tenanted, Role-Based Access Control System",
		description: "TomDoesTech",
		time: "2:01:29"
	},
	/*
	This video became private
	Uncomment (in other files too) it when it becomes public again
	{
		id: "3tl9XCiQErA",
		title: "The Prisma killer is finally here",
		description: "SST",
		time: "5:42"
	},
	*/
	{
		id: "VQFjyEa8vGE",
		title: "Learning Drizzle ORM and working on a next14 project",
		description: "Web Dev Cody",
		time: "1:07:41"
	},
	{
		id: "5G0upg4sxgE",
		title: "This Trick Makes My Favorite Database Tool Even Better",
		description: "Josh tried coding",
		time: "6:01"
	},
	{
		id: "-JnEuvPmt-Q",
		title: "Effortless Auth in Next.js 14: Use Auth.js & Drizzle ORM for Secure Login",
		description: "Sam Meech-Ward",
		time: "26:29"
	},
]} />


Source: https://orm.drizzle.team/docs/sqlite/perf-queries

# Query performance
When it comes to **Drizzle** — we're a thin TypeScript layer on top of SQL with 
almost 0 overhead and to make it actual 0, you can utilise our prepared statements API.
  
**When you run a query on the database, there are several things that happen:**
- all the configurations of the query builder got concatenated to the SQL string
- that string and params are sent to the database driver
- driver compiles SQL query to the binary SQL executable format and sends it to the database

With prepared statements you do SQL concatenation once on the Drizzle ORM side and then database 
driver is able to reuse precompiled binary SQL instead of parsing query all the time. 
It has extreme performance benefits on large SQL queries.  

Different database drivers support prepared statements in different ways and sometimes 
Drizzle ORM you can go [**faster than better-sqlite3 driver.**](https://twitter.com/_alexblokh/status/1593593415907909634)

## Prepared statement

```typescript copy {3}
    const db = drizzle(...);

    const prepared = db.select().from(customers).prepare();
    
    const res1 = prepared.all();
    const res2 = prepared.all();
    const res3 = prepared.all();
    ```

## Placeholder
Whenever you need to embed a dynamic runtime value - you can use the `sql.placeholder(...)` api

```ts copy {6,9-10,15,18}
    import { sql } from "drizzle-orm";

    const p1 = db
      .select()
      .from(customers)
      .where(eq(customers.id, sql.placeholder('id')))
      .prepare()

    p1.get({ id: 10 }) // SELECT * FROM customers WHERE id = 10
    p1.get({ id: 12 }) // SELECT * FROM customers WHERE id = 12

    const p2 = db
      .select()
      .from(customers)
      .where(sql`lower(${customers.name}) like ${sql.placeholder('name')}`)
      .prepare();

    p2.all({ name: '%an%' }) // SELECT * FROM customers WHERE lower(name) like '%an%'
    ```


Source: https://orm.drizzle.team/docs/sqlite/query-utils

import $count from '@mdx/$count-sqlite.mdx';

# Drizzle query utils

### $count
<$count/>

Source: https://orm.drizzle.team/docs/sqlite/read-replicas

# Read Replicas

When your project involves a set of read replica instances, and you require a convenient method for managing 
SELECT queries from read replicas, as well as performing create, delete, and update operations on the primary 
instance, you can leverage the `withReplicas()` function within Drizzle

```ts copy
import { sql } from 'drizzle-orm';
import { sqliteTable, int, text, withReplicas } from 'drizzle-orm/sqlite-core';
import { createClient } from '@libsql/client';
import { drizzle } from 'drizzle-orm/libsql';

const usersTable = sqliteTable('users', {
	id: int().primaryKey(),
	name: text().notNull(),
});

const primaryDb = drizzle({ client: createClient({ url: 'DATABASE_URL', authToken: 'DATABASE_AUTH_TOKEN' }) });
const read1 = drizzle({ client: createClient({ url: 'DATABASE_URL', authToken: 'DATABASE_AUTH_TOKEN' }) });
const read2 = drizzle({ client: createClient({ url: 'DATABASE_URL', authToken: 'DATABASE_AUTH_TOKEN' }) });

const db = withReplicas(primaryDb, [read1, read2]);
```

You can now use the `db` instance the same way you did before. Drizzle will 
handle the choice between read replica and the primary instance automatically

```ts
// Read from either the read1 connection or the read2 connection
await db.select().from(usersTable)

// Use the primary database for the delete operation
await db.delete(usersTable).where(eq(usersTable.id, 1))
```

You can use the `$primary` key to force using primary instances even for read operations

```ts
// read from primary
await db.$primary.select().from(usersTable);
```

With Drizzle, you can also specify custom logic for choosing read replicas. 
You can make a weighted decision or any other custom selection method for random read replica choice. 
Here is an 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 selected.

Keep in mind that you can implement any type of random selection method 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]!
});

await db.select().from(usersTable)
```


Source: https://orm.drizzle.team/docs/sqlite/relations-schema-declaration

import Tab from '@mdx/Tab.astro';
import Tabs from '@mdx/Tabs.astro';
import Callout from '@mdx/Callout.astro';
import SimpleLinkCards from '@mdx/SimpleLinkCards.astro';
import CodeTabs from "@mdx/CodeTabs.astro";
import Section from '@mdx/Section.astro';
import Flex from "@mdx/Flex.astro"
import LinksList from "@mdx/LinksList.astro"

# Drizzle Relations Fundamentals

In the world of databases, especially relational databases, the concept of relations is absolutely fundamental.
Think of "relations" as the connections and links between different pieces of data. Just like in real life, 
where people have relationships with each other, or objects are related to categories, databases use relations to model how different 
types of information are connected and work together.

### Normalization
Normalization is the process of organizing data in your database to reduce redundancy (duplication) and improve data integrity 
(accuracy and consistency). Think of it like tidying up a messy filing cabinet. Instead of having all sorts of papers 
crammed into one folder, you organize them into logical folders and categories to make everything easier to find and manage.

<Callout collapsed="Why is Normalization Important?">
- **Reduces Data Redundancy**: Imagine storing a customer's address every time they place an order. If the address changes, you'd have to update it in multiple places! Normalization helps you store information in one place and refer to it from other places, minimizing repetition.
- **Improves Data Integrity**: Less redundancy means less chance of inconsistencies. If you update an address in one place, it's updated everywhere it's needed.
- **Prevents Anomalies**: Normalization helps prevent issues like:
  1. **Insertion Anomalies**: Difficulty adding new data because you're missing related information.
  2. **Update Anomalies**: Having to update the same information in multiple rows.
  3. **Deletion Anomalies**: Accidentally losing valuable information when you delete something seemingly unrelated.
- **Easier to Understand and Maintain**: A normalized database is generally more logically structured and easier to understand, query, and modify.
</Callout>

Normalization is often described in terms of "normal forms" (1NF, 2NF, 3NF, and beyond). While the details can get quite technical, the core ideas are straightforward:

#### 1NF (First Normal Form): `Atomic Values`

**Goal**: Each column should hold a single, indivisible value. No repeating groups of data within a single cell

**Example**: Instead of having a single `address` column that stores `123 Main St, City, USA`, you'd 
break it down into separate columns: `street_address`, `city`, `state`, `zip_code`.

```sql
-- Unnormalized (violates 1NF)
CREATE TABLE Customers_Unnormalized (
    customer_id INTEGER PRIMARY KEY,
    name TEXT,
    address TEXT -- Problem: Multiple pieces of info in one column
);

-- Normalized to 1NF
CREATE TABLE Customers_1NF (
    customer_id INTEGER PRIMARY KEY,
    name TEXT,
    street_address TEXT,
    city TEXT,
    state TEXT,
    zip_code TEXT
);
```

#### 2NF (Second Normal Form): `Eliminate Redundant Data Dependent on Part of the Key`

**Goal**: Applies when you have a table with a composite primary key (a primary key made up of two or more columns). 
2NF ensures that all non-key attributes are fully dependent on the entire composite primary key, not just part of it.

Imagine we have a table called `order_items`. This table tracks items within orders, and we use a composite primary key (`order_id`, `product_id`) 
because a single order can have multiple of the same product (though in this simplified example, let's assume each product appears only 
once per order for clarity, but the composite key logic still applies).

<Callout collapsed="Expand for visual example">
```sql
CREATE TABLE OrderItems_Unnormalized (
    order_id INTEGER,
    product_id TEXT,
    product_name TEXT,
    product_price REAL,
    quantity INTEGER,
    order_date TEXT,
    PRIMARY KEY (order_id, product_id) -- Composite Primary Key
);

INSERT INTO OrderItems_Unnormalized (order_id, product_id, product_name, product_price, quantity, order_date) VALUES
(101, 'A123', 'Laptop', 1200.00, 1, '2023-10-27'),
(101, 'B456', 'Mouse', 25.00, 2, '2023-10-27'),
(102, 'A123', 'Laptop', 1200.00, 1, '2023-10-28'),
(103, 'C789', 'Keyboard', 75.00, 1, '2023-10-29');
```
```
+------------------------------------------------------------------------------------+
| OrderItems_Unnormalized                                                            |
+------------------------------------------------------------------------------------+
| PK (order_id, product_id) | product_name | product_price | quantity | order_date   |
+------------------------------------------------------------------------------------+
| 101, A123               | Laptop       | 1200.00       | 1        | 2023-10-27     |
| 101, B456               | Mouse        | 25.00         | 2        | 2023-10-27     |
| 102, A123               | Laptop       | 1200.00       | 1        | 2023-10-28     |
| 103, C789               | Keyboard     | 75.00         | 1        | 2023-10-29     |
+------------------------------------------------------------------------------------+
```
</Callout>

**Problem**: Notice that `product_name` and `product_price` are repeated whenever the same `product_id` appears in different orders. 
These attributes are only dependent on `product_id`, which is part of the composite primary key (`order_id`, `product_id`), but not the entire key. 
This is a partial dependency.

To achieve 2NF, we need to remove the partially dependent attributes (`product_name`, `product_price`) and place them in a separate table where they are 
fully dependent on the primary key of that new table.

<Callout collapsed="Normalization to 2NF: Visual explanation">
```
+-------------------+     1:M     +---------------------------+
| Products          | <---------- | OrderItems_2NF            |
+-------------------+             +---------------------------+
| PK product_id     |             | PK (order_id, product_id) |
| product_name      |             | quantity                  |
| product_price     |             | order_date                |
+-------------------+             | FK product_id             |
                                  +---------------------------+
```
```sql
CREATE TABLE Products (
    product_id TEXT PRIMARY KEY,
    product_name TEXT,
    product_price REAL
);

CREATE TABLE OrderItems_2NF (
    order_id INTEGER,
    product_id TEXT,
    quantity INTEGER,
    order_date TEXT,
    PRIMARY KEY (order_id, product_id), -- Composite Primary Key remains
    FOREIGN KEY (product_id) REFERENCES Products(product_id) -- Foreign Key to Products
);

-- Insert data into Products
INSERT INTO Products (product_id, product_name, product_price) VALUES
('A123', 'Laptop', 1200.00),
('B456', 'Mouse', 25.00),
('C789', 'Keyboard', 75.00);

-- Insert data into OrderItems_2NF (referencing Products)
INSERT INTO OrderItems_2NF (order_id, product_id, quantity, order_date) VALUES
(101, 'A123', 1, '2023-10-27'),
(101, 'B456', 2, '2023-10-27'),
(102, 'A123', 1, '2023-10-28'),
(103, 'C789', 1, '2023-10-29');
```
</Callout>

#### 3NF (Third Normal Form): `Eliminate Redundant Data Dependent on Non-Key Attributes`

**Goal**: Remove data that is dependent on other non-key attributes. This is about eliminating transitive dependencies.

**Problem**: Let's say we have a `suppliers` table. We store supplier information, including their `zip_code`, `city`, and `state`. `supplier_id` is the primary key.

<Callout collapsed="">
```sql
CREATE TABLE suppliers (
    supplier_id TEXT PRIMARY KEY,
    supplier_name TEXT,
    zip_code TEXT,
    city TEXT,
    state TEXT
);

INSERT INTO suppliers (supplier_id, supplier_name, zip_code, city, state) VALUES
('S1', 'Acme Corp', '12345', 'Anytown', 'NY'),
('S2', 'Beta Inc', '67890', 'Otherville', 'CA'),
('S3', 'Gamma Ltd', '12345', 'Anytown', 'NY');
```
```
+---------------------------------------------------------------+
| suppliers                                                     |
+---------------------------------------------------------------+
| PK supplier_id | supplier_name | zip_code | city      | state |
+---------------------------------------------------------------+
| S1             | Acme Corp     | 12345    | Anytown    | NY   |
| S2             | Beta Inc      | 67890    | Otherville | CA   |
| S3             | Gamma Ltd     | 12345    | Anytown    | NY   |
+---------------------------------------------------------------+
```
</Callout>

**Solution**: To achieve 3NF, we remove the attributes dependent on the non-key attribute (`city`, `state` dependent on `zip_code`) and put 
them into a separate table keyed by the non-key attribute itself (`zip_code`).

<Callout collapsed="Normalization to 3NF: Visual explanation">
```
+-------------------+     1:M     +--------------------+
| zip_codes         | <---------- | suppliers          |
+-------------------+             +--------------------+
| PK zip_code       |             | PK supplier_id     |
| city              |             | supplier_name      |
| state             |             | FK zip_code        |
+-------------------+             +--------------------+
```
```sql
CREATE TABLE zip_codes (
    zip_code TEXT PRIMARY KEY,
    city TEXT,
    state TEXT
);

CREATE TABLE suppliers (
    supplier_id TEXT PRIMARY KEY,
    supplier_name TEXT,
    zip_code TEXT, -- Foreign Key to zip_codes
    FOREIGN KEY (zip_code) REFERENCES zip_codes(zip_code)
);

-- Insert data into zip_codes
INSERT INTO zip_codes (zip_code, city, state) VALUES
('12345', 'Anytown', 'NY'),
('67890', 'Otherville', 'CA');

-- Insert data into suppliers (referencing zip_codes)
INSERT INTO suppliers (supplier_id, supplier_name, zip_code) VALUES
('S1', 'Acme Corp', '12345'),
('S2', 'Beta Inc', '67890'),
('S3', 'Gamma Ltd', '12345');
```
</Callout>

<Callout title="Good to know">
There are additional normal forms, such as `4NF`, `5NF`, `6NF`, `EKNF`, `ETNF`, and `DKNF`. We won't cover these here, but we will create a 
dedicated set of tutorials for them in our guides and tutorials section.
</Callout>

### Database Relationships
#### One-to-One

In a one-to-one relationship, each record in `table A` is related to at most one record in `table B`, and each record in `table B` is
related to at most one record in `table A`. It's a very direct, exclusive pairing.

<Callout collapsed="Use Cases & Examples">
1. **User Profiles and User Account Details**: Think of a website. Each user account (in a Users table) might have exactly one user profile (in a UserProfiles table) containing more detailed information.
2. **Employees and Parking Spaces**: An Employees table and a ParkingSpaces table. Each employee might be assigned at most one parking space, and each parking space is assigned to at most one employee.
3. **Splitting Tables for Organization**: Sometimes, you might split a very wide table into two for better organization or security reasons, maintaining a 1-1 relationship between them.

```
Table A (One Side)      Table B (One Side)
+---------+             +---------+
| PK (A)  | <---------> | FK (A)  | (Foreign Key referencing Table A)
| ...     |             | ...     |
+---------+             +---------+
```
</Callout>


#### One-to-Many

In a one-to-many relationship, one record in `table A` can be related to many records in `table B`, but each 
record in `table B` is related to at most one record in `table A`. Think of it as a "parent-child" relationship.

<Callout collapsed="Use Cases & Examples">
1. **Customers and Orders**: One customer can place many orders, but each order belongs to only one customer.
2. **Authors and Books**: One author can write many books, but (let's simplify for now and say) each book is written by one primary author.
3. **Departments and Employees**: One department can have many employees, but each employee belongs to only one department.

```
Table A (One Side)      Table B (Many Side)
+---------+             +---------+
| PK (A)  | ----------> | FK (A)  | (Foreign Key referencing Table A)
| ...     |             | ...     |
+---------+             +---------+
     (One)                  (Many)
```
</Callout>

#### Many-to-Many

In a many-to-many relationship, one record in `table A` can be related to many records in `table B`, and one 
record in `table B` can be related to many records in `table A`. It's a more complex, bidirectional relationship.

<Callout collapsed="Use Cases & Examples">
1. **Students and Courses**: One student can enroll in many courses, and one course can have many students enrolled.
2. **Products and Categories**: One product can belong to multiple categories (e.g., a "T-shirt" can be
in "Clothing" and "Summer Wear" categories), and one category can contain many products.
3. **Authors and Books**: A book can be written by multiple authors, and an author can write multiple books.

```
Table A (Many Side)    Junction Table      Table B (Many Side)
+---------+          +-------------+     +---------+
| PK (A)  | -------->| FK (A)      | <----| FK (B)  |
| ...     |          | FK (B)      |     | ...     |
+---------+          +-------------+     +---------+
     (Many)             (Junction)          (Many)
```
</Callout>

Many-to-many relationships are not directly implemented with foreign keys between the two main tables. 
Instead, you need a `junction` table (also called an associative table or bridging table). 
This table acts as an intermediary to link records from both tables.

```sql
-- Table for Students (Many side)
CREATE TABLE students (
    id INTEGER PRIMARY KEY,
    name TEXT
);

-- Table for Courses (Many side)
CREATE TABLE courses (
    id INTEGER PRIMARY KEY,
    name TEXT,
    credits INTEGER
);

-- Junction Table: Enrollments (Connects Students and Courses - M-M relationship)
CREATE TABLE enrollments (
    id INTEGER PRIMARY KEY AUTOINCREMENT, -- Optional, but good practice for junction tables
    student_id INTEGER,
    course_id INTEGER,
    enrollment_date TEXT,
    -- Composite Foreign Keys (often part of a composite primary key or unique constraint)
    FOREIGN KEY (student_id) REFERENCES students(id),
    FOREIGN KEY (course_id) REFERENCES courses(id),
    UNIQUE (student_id, course_id) -- Prevent duplicate enrollments for the same student and course
);
```

### Why Foreign Keys?

You might think of foreign key constraints as simply a way to validate data - ensuring 
that when you enter a value in a foreign key column, that value actually exists in the primary key 
column of another table. And you'd be partially right! This value checking is the mechanism foreign keys use.

But it's crucial to understand that this validation is not the end goal, it's the means 
to a much larger purpose. Foreign key constraints are fundamentally about:

<Callout collapsed="1. Explicitly Defining and Enforcing Relationships">

We've discussed relationships like `One-to-Many` between Customers and Orders. 
A foreign key is the SQL language's way of telling the database: 

> Hey database, I want to enforce a 1-M relationship here. Every value in the customer_id column of the
Orders table must correspond to a valid customer_id in the Customers table.

It's not just a suggestion; it's a constraint the database actively enforces. 
The database becomes relationship-aware because of the foreign key.
</Callout>

<Callout collapsed="2. Maintaining Referential Integrity">
- This is the core of "data integrity" in the context of relationships. Referential integrity means 
that relationships between tables remain consistent and valid over time.
- Foreign keys prevent orphaned records. What's an orphaned record? In our Customer-Order example, 
an order that exists in the Orders table but doesn't have a corresponding customer in the Customers 
table would be an orphan. Foreign keys prevent this from happening (or control what happens 
if you try to delete a customer with orders - via CASCADE, SET NULL, etc.).
- Why is preventing orphans important? Orphaned records break the logical structure of your data. 
If you have an order without a customer, you lose crucial context. Queries become unreliable, reports
 become inaccurate, and your application's logic can break down.

**Example**:
```
Without a foreign key, you could accidentally delete a customer from the Customers 
table while their orders still exist in the Orders table. Suddenly, you have orders that point to 
a customer that no longer exists! A foreign key constraint prevents this data inconsistency.
```
</Callout>

<Callout collapsed="3. Facilitating Database Design and Understanding">
- Foreign keys are not just about technical enforcement; they are also a crucial part of database design documentation.
- When you see a foreign key in a database schema, it immediately tells you: 
`Table 'X' is related to Table 'Y' in this way.` It's a clear visual and structural indicator of relationships.
- This makes databases easier to understand, maintain, and evolve over time. New developers can quickly 
grasp how different parts of the database are connected.
</Callout>

In essence, foreign key constraints are not just about checking values; they are about:

1. Defining the rules of your data relationships
2. Actively enforcing those rules at the database level
3. Guaranteeing data integrity and consistency within those relationships
4. Making your database more robust, reliable, and understandable

### Why NOT Foreign Keys?

While highly beneficial, there are some scenarios where you might reconsider or use Foreign Keys with caution. 
These are typically edge cases and often involve trade-offs.

<Callout collapsed="1. Performance Overhead in Very High-Write Environments">
- **Scenario**: Extremely high-volume transactional systems (e.g., real-time logging, very high-frequency trading
platforms, massive IoT data ingestion).
- **Explanation**: Every time you insert or update data in a table with a foreign key, the database system 
needs to perform checks to ensure referential integrity. In extremely high-write scenarios, these 
checks can introduce a small but potentially noticeable performance overhead.
</Callout>

<Callout collapsed="2. Distributed Database Systems and Cross-Node Foreign Keys:">
- **Scenario**: Systems where data is distributed across multiple database nodes or clusters (common in sharded databases, cloud environments, and microservices).
- **Explanation**:  Cross-node foreign keys can introduce significant complexity and performance overhead. Validating referential integrity requires communication between nodes, leading to increased latency. Distributed transactions needed to maintain consistency are also more complex and can be less performant than local transactions. In such architectures, application-level data integrity checks or eventual consistency models might be considered alternatives.
</Callout>

<Callout collapsed="3. Legacy Systems and Data Integration with Non-Relational Data:">
- **Scenario**: Integrating a relational database with older legacy systems or non-relational data stores (e.g., NoSQL, flat files, external APIs).
- **Explanation**:  Legacy systems or non-relational data might not consistently adhere to the referential integrity rules enforced by foreign keys.  Imposing foreign keys in such scenarios can lead to data import issues, data inconsistencies, and might necessitate complex data transformation or application-level integrity management instead. You might need to carefully evaluate the data quality and consistency of the external sources and potentially rely on application logic or ETL processes to ensure data integrity instead of strictly enforcing foreign keys at the database level.
</Callout>

You can also check out some great explanations from the PlanetScale team in their [article](https://planetscale.com/docs/learn/operating-without-foreign-key-constraints#why-does-planetscale-not-recommend-constraints)

### Polymorphic Relations

Polymorphic relationships are a more advanced concept that allows a single relationship to point to 
different types of entities or tables. It's about creating more flexible and adaptable relationships when 
you have different kinds of data that share some commonality.

Imagine you have an `activities` log. An activity could be a `comment` a `like` or a `share`.
Each of these `activity` types has different details. Instead of creating separate tables and 
relationships for each activity type and the things they relate to, you might use a polymorphic approach.

<Callout collapsed="Common Scenarios & Examples">
- **Comments/Reviews**: A "Comment" might be related to different types of content: articles, products, videos, etc. 
Instead of having separate article_id, product_id, video_id columns in a Comments table, you can use a 
polymorphic relationship.
```
+---------------------+
| **Comments**        |
+---------------------+
| PK comment_id       |
| commentable_type    | ------>  [Polymorphic Relationship]
| commentable_id      | -------->
| user_id             |
| comment_text        |
| ...                 |
+---------------------+
          ^
          |
+---------------------+    +---------------------+    +---------------------+
| **Articles**        |    | **Products**        |    | **Videos**          |
+---------------------+    +---------------------+    +---------------------+
| PK article_id       |    | PK product_id       |    | PK video_id         |
| ...                 |    | ...                 |    | ...                 |
+---------------------+    +---------------------+    +---------------------+
```
- **Notifications:** A notification could be related to a user, an order, a system event, etc.
```
+----------------------+
| **Notifications**    |
+----------------------+
| PK notification_id  |
| notifiable_type     | ------>  [Polymorphic Relationship]
| notifiable_id       | -------->
| user_id             |
| message             |
| ...                  |
+----------------------+
           ^
           |
+---------------------+    +---------------------+    +-----------------------+
| **Users**           |    | **Orders**          |    | **System Events**     |
+---------------------+    +---------------------+    +-----------------------+
| PK user_id          |    | PK order_id         |    | PK event_id           |
| ...                 |    | ...                 |    | ...                   |
+---------------------+    +---------------------+    +-----------------------+
```
</Callout>

Polymorphic relationships are more complex and are often handled at the application level or 
using more advanced database features (depending on the specific database system). Standard SQL doesn't 
have direct, built-in support for enforcing polymorphic foreign key constraints in the same way as regular foreign keys.

Source: https://orm.drizzle.team/docs/sqlite/relations-v1-v2

import Callout from '@mdx/Callout.astro';
import Prerequisites from "@mdx/Prerequisites.astro";
import Section from '@mdx/Section.astro';
import Npx from "@mdx/Npx.astro";
import Npm from "@mdx/Npm.astro";
import CodeTabs from '@mdx/CodeTabs.astro';
import CodeTab from '@mdx/CodeTab.astro';

# Migrating to Relational Queries version 2

<Npm>
 drizzle-orm@rc
 drizzle-kit@rc -D
</Npm>

<br/>

<Prerequisites>
- **Relations Fundamentals** - [read here](/docs/sqlite/relations-schema-declaration)
- **drizzle-kit pull** - [read here](/docs/sqlite/drizzle-kit-pull)
</Prerequisites>

<Callout>
Below is the table of contents. Click an item to jump to that section:

- [What is working differently from v1](#what-is-working-differently-from-v1)  
- [New features in v2](#what-is-new)  
- [How to migrate relations definition from v1 to v2](#how-to-migrate-relations-schema-definition-from-v1-to-v2)  
- [How to migrate queries from v1 to v2](#how-to-migrate-queries-from-v1-to-v2)  
- [Internal changes(imports, internal types, etc.)](#internal-changes)
</Callout>

### API changes
#### What is working differently from v1

{/* ##### Drizzle Relations schema definition */}

One of the biggest updates were in **Relations Schema definition**

The first difference is that you no longer need to specify `relations` for each table separately in different objects and
then pass them all to `drizzle()` along with your schema. In Relational Queries v2, you now have one dedicated place to
specify all the relations for all the tables you need.

The `r` parameter in the callback provides comprehensive autocomplete
functionality - including all tables from your schema and functions such as `one`, `many`, and `through` - essentially
offering everything you need to specify your relations.

```ts
// relations.ts
import * as schema from "./schema"
import { defineRelations } from "drizzle-orm"

export const relations = defineRelations(schema, (r) => ({
    ...
}));
```
```ts
// index.ts
import { relations } from "./relations"
import { drizzle } from "drizzle-orm/..."

const db = drizzle(process.env.DATABASE_URL, { relations })
```

##### What is different?

<Callout collapsed="Schema Definition">
```ts copy
import * as p from 'drizzle-orm/sqlite-core';

export const users = p.sqliteTable('users', {
  id: p.integer().primaryKey(),
  name: p.text(),
  invitedBy: p.integer('invited_by'),
});

export const posts = p.sqliteTable('posts', {
  id: p.integer().primaryKey(),
  content: p.text(),
  authorId: p.integer('author_id'),
});
```
</Callout>

**One place for all your relations**

<Callout title="❌ v1">
```ts
import { relations } from "drizzle-orm/_relations";
import { users, posts } from './schema';

export const usersRelation = relations(users, ({ one, many }) => ({
  invitee: one(users, {
    fields: [users.invitedBy],
    references: [users.id],
  }),
  posts: many(posts),
}));

export const postsRelation = relations(posts, ({ one, many }) => ({
  author: one(users, {
    fields: [posts.authorId],
    references: [users.id],
  }),
}));
```
</Callout>

<Callout title='✅ v2'>
```ts
import { defineRelations } from "drizzle-orm";
import * as schema from "./schema";

export const relations = defineRelations(schema, (r) => ({
  users: {
    invitee: r.one.users({
      from: r.users.invitedBy,
      to: r.users.id,
    }),
    posts: r.many.posts(),
  },
  posts: {
    author: r.one.users({
      from: r.posts.authorId,
      to: r.users.id,
    }),
  },
}));
```
</Callout>

You can still separate it into different `parts`, and you can make the parts any size you want

```ts
import { defineRelations, defineRelationsPart } from 'drizzle-orm';
import * as schema from "./schema";

export const relations = defineRelations(schema, (r) => ({
  users: {
    invitee: r.one.users({
      from: r.users.invitedBy,
      to: r.users.id,
    }),
    posts: r.many.posts(),
  }
}));

export const part = defineRelationsPart(schema, (r) => ({
  posts: {
    author: r.one.users({
      from: r.posts.authorId,
      to: r.users.id,
    }),
  }
}));
```

and then you can provide it to the db instance

```ts
const db = drizzle(process.env.DB_URL, { relations: { ...relations, ...part } })
```

**Define `many` without `one`**

In v1, if you wanted only the `many` side of a relationship, you had to specify the `one` side on the other end, 
which made for a poor developer experience.

In v2, you can simply use the `many` side without any additional steps

<Callout title="❌ v1">
```ts
import { relations } from "drizzle-orm/_relations";
import { users, posts } from './schema';

export const usersRelation = relations(users, ({ one, many }) => ({
  posts: many(posts),
}));

export const postsRelation = relations(posts, ({ one, many }) => ({
  author: one(users, {
    fields: [posts.authorId],
    references: [users.id],
  }),
}));
```
</Callout>

<Callout title='✅ v2'>
```ts
import { defineRelations } from "drizzle-orm";
import * as schema from "./schema";

export const relations = defineRelations(schema, (r) => ({
  users: {
    posts: r.many.posts({
      from: r.users.id,
      to: r.posts.authorId,
    }),
  },
}));
```
</Callout>

**New `optional` option**

`optional: false` at the type level makes the `author` key in the `posts` object required. 
This should be used when you are certain that this specific entity will always exist.

<Callout title="❌ v1">
Was not supported in v1
</Callout>

<Callout title='✅ v2'>
```ts {9}
import { defineRelations } from "drizzle-orm";
import * as schema from "./schema";

export const relations = defineRelations(schema, (r) => ({
  users: {
    posts: r.one.posts({
      from: r.users.id,
      to: r.posts.authorId,
      optional: false,
    }),
  },
}));
```
</Callout>

**No modes in `drizzle()`**

We found a way to use the same strategy for all MySQL dialects, so there's no need to specify them

<Callout title="❌ v1">
```ts
import * as schema from './schema'

const db = drizzle(process.env.DATABASE_URL, { mode: "planetscale", schema });
// or
const db = drizzle(process.env.DATABASE_URL, { mode: "default", schema });
```
</Callout>

<Callout title='✅ v2'>
```ts
import { relations } from './relations'

const db = drizzle(process.env.DATABASE_URL, { relations });
```
</Callout>

**`from` and `to` upgrades**

We've renamed `fields` to `from` and `references` to `to`, and we made both accept either a single value or an array

<Callout title="❌ v1">
```ts
...
author: one(users, {
  fields: [posts.authorId],
  references: [users.id],
}),
...
```
</Callout>

<Callout title='✅ v2'>
```ts
... 
author: r.one.users({
  from: r.posts.authorId,
  to: r.users.id,
}),
...
```
```ts
... 
author: r.one.users({
  from: [r.posts.authorId],
  to: [r.users.id],
}),
...
```
</Callout>

**`relationName` -> `alias`**

<Callout title="❌ v1">
```ts {8}
import { relations } from "drizzle-orm/_relations";
import { users, posts } from './schema';

export const postsRelation = relations(posts, ({ one }) => ({
  author: one(users, {
    fields: [posts.authorId],
    references: [users.id],
	  relationName: "author_post",
  }),
}));
```
</Callout>

<Callout title='✅ v2'>
```ts {9}
import { defineRelations } from "drizzle-orm";
import * as schema from "./schema";

export const relations = defineRelations(schema, (r) => ({
  posts: {
    author: r.one.users({
      from: r.posts.authorId,
      to: r.users.id,
      alias: "author_post",
    }),
  },
}));
```
</Callout>

**`custom types` new functions**

There are a few new function were added to custom types, so you can control how data is mapped on Relational Queries v2:

<Callout collapsed='fromJson'>
Optional mapping function, that is used for transforming data returned by transofmed to JSON in database data to desired format
For example, when querying blob column via [RQB](/docs/sqlite/rqb) or JSON functions, the result field will be returned as it's hex string representation, as opposed to Buffer from regular query
To handle that, we need a separate function to handle such field's mapping:
```ts
fromJson(value: string): Buffer {
	return Buffer.from(value, 'hex');
},
```
It'll cause the returned data to change from:
```
{
	customField: "04A8...";
}
```
to:
```
{
	customField: Buffer([...]);
}
```
</Callout> 
<Callout collapsed='forJsonSelect'>
Optional selection modifier function, that is used for modifying selection of column inside JSON functions
Additional mapping that could be required for such scenarios can be handled using fromJson function
Used by [relational queries](/docs/sqlite/rqb)

```ts
forJsonSelect(identifier: SQL, sql: SQLGenerator): SQL {
 	return sql`cast(${identifier} as text)`
 },
 ```

 This will change query from:
 ``` sql
 SELECT
 	json_object('bigint', `t`.`bigint`)
 	FROM
 	(
 		SELECT
 		`table`.`custom_bigint` AS "bigint"
 		FROM
 		`table`
 	) AS `t`
 ```
 to:
 ``` sql
 SELECT
 	json_object('bigint', `t`.`bigint`)
 	FROM
 	(
 		SELECT
 		cast(`table`.`custom_bigint` as text) AS `bigint`
 		FROM
 		`table`
 	) AS `t`
 ```
Returned by query object will change from:
```ts
{
	bigint: 5044565289845416000; // Partial data loss due to direct conversion to JSON format
}
```
to:
```ts
{
	bigint: "5044565289845416380"; // Data is preserved due to conversion of field to text before JSON-ification
}
```
</Callout>

<Callout title='✅ v2'>
```ts
const customBytes = customType<{
 	data: Buffer;
 	driverData: Buffer;
 	jsonData: string;
 }>({
 	dataType: () => 'custom',
 	fromJson: (value) => {
 		return Buffer.from(value.slice(2, value.length), 'hex');
 	},
 	forJsonSelect: (identifier, sql, arrayDimensions) =>
 		sql`cast(${identifier} as text)`,
 });
```

</Callout>

##### What is new?

**`through` for many-to-many relations**

Previously, you would need to query through a junction table and then map it out for every response

You don't need to do it now!

<Callout collapsed='Schema'>
```ts
import * as p from 'drizzle-orm/sqlite-core';

export const users = p.sqliteTable('users', {
  id: p.integer().primaryKey(),
  name: p.text(),
  verified: p.boolean().notNull(),
});

export const groups = p.sqliteTable('groups', {
  id: p.integer().primaryKey(),
  name: p.text(),
});

export const usersToGroups = p.sqliteTable(
  'users_to_groups',
  {
    userId: p
      .integer('user_id')
      .notNull()
      .references(() => users.id),
    groupId: p
      .integer('group_id')
      .notNull()
      .references(() => groups.id),
  },
  (t) => [p.primaryKey({ columns: [t.userId, t.groupId] })]
);
```
</Callout>

<Callout title="❌ v1">
```ts
export const usersRelations = relations(users, ({ many }) => ({
  usersToGroups: many(usersToGroups),
}));

export const groupsRelations = relations(groups, ({ many }) => ({
  usersToGroups: many(usersToGroups),
}));

export const usersToGroupsRelations = relations(usersToGroups, ({ one }) => ({
  group: one(groups, {
    fields: [usersToGroups.groupId],
    references: [groups.id],
  }),
  user: one(users, {
    fields: [usersToGroups.userId],
    references: [users.id],
  }),
}));
```
```ts
// Query example
const response = await db.query.users.findMany({
  with: {
    usersToGroups: {
      columns: {},
      with: {
        group: true,
      },
    },
  },
});
```
</Callout>

<Callout title='✅ v2'>
```ts
import * as schema from './schema';
import { defineRelations } from 'drizzle-orm';

export const relations = defineRelations(schema, (r) => ({
  users: {
    groups: r.many.groups({
      from: r.users.id.through(r.usersToGroups.userId),
      to: r.groups.id.through(r.usersToGroups.groupId),
    }),
  },
  groups: {
    participants: r.many.users(),
  },
}));
```
```ts
// Query example
const response = await db.query.users.findMany({
  with: {
    groups: true,
  },
});
```
</Callout>

**Predefined filters**

<Callout title="❌ v1">
Was not supported in v1
</Callout>

<Callout title='✅ v2'>
```ts {10-12}
import * as schema from './schema';
import { defineRelations } from 'drizzle-orm';

export const relations = defineRelations(schema,
  (r) => ({
    groups: {
      verifiedUsers: r.many.users({
        from: r.groups.id.through(r.usersToGroups.groupId),
        to: r.users.id.through(r.usersToGroups.userId),
        where: {
          verified: true,
        },
      }),
    },
  })
);
```
```ts {4}
// Query example: get groups with all verified users
const response = await db.query.groups.findMany({
  with: {
    verifiedUsers: true,
  },
});
```
</Callout>

##### `where` is now object

<Callout title="❌ v1">
```ts
const response = db._query.users.findMany({
  where: (users, { eq }) => eq(users.id, 1),
});
```
</Callout>

<Callout title="✅ v2">
```ts
const response = db.query.users.findMany({
  where: {
    id: 1,
  },
});
```

For a complete API Reference please check our [Select Filters docs](/docs/sqlite/rqb#select-filters)
</Callout>

<Callout collapsed='Complex filter example using RAW'>
```ts
// schema.ts
import { integer, json, sqliteTable, text, timestamp } from 'drizzle-orm/sqlite-core';

export const users = sqliteTable('users', {
  id: integer().primaryKey(),
  name: text(),
  email: text().notNull(),
  age: integer(),
  createdAt: timestamp('created_at').defaultNow(),
  lastLogin: timestamp('last_login'),
  subscriptionEnd: timestamp('subscription_end'),
  lastActivity: timestamp('last_activity'),
  preferences: text({ mode: "json" }), // JSON column for user settings/preferences
  interests: text({ mode: "json" }).$type<string[]>(), // Array column for user interests
});
```
```ts
const response = await db.query.users.findMany({
    where: {
      AND: [
        {
          OR: [{ RAW: (table) => sql`${table.name} LIKE 'john%'` }, { name: { like: "jane%" } }],
        },
        { 
          RAW: (table) => sql`${table.age} BETWEEN 25 AND 35` 
        }
      ]
    }
  })
```
</Callout>

##### `orderBy` is now object

<Callout title="❌ v1">
```ts
const response = db._query.users.findMany({
  orderBy: (users, { asc }) => [asc(users.id)],
});
```
</Callout>

<Callout title="✅ v2">
```ts
const response = db.query.users.findMany({
  orderBy: { id: "asc" },
});
```
</Callout>

##### Filtering by relations

<Callout title="❌ v1">
Was not supported in v1
</Callout>

<Callout title='✅ v2'>
Example: Get all users whose ID>10 and who have at least one post with content starting with “M”

```ts
const usersWithPosts = await db.query.usersTable.findMany({
  where: {
    id: {
      gt: 10
    },
    posts: {
      content: {
        like: 'M%'
      }
    }
  },
});
```
</Callout>

##### Using offset on related objects

<Callout title="❌ v1">
Was not supported in v1
</Callout>

<Callout title='✅ v2'>
```ts
await db.query.posts.findMany({
	limit: 5,
	offset: 2, // correct ✅
	with: {
		comments: {
			offset: 3, // correct ✅
			limit: 3,
		},
	},
});
```
</Callout>

#### How to migrate relations schema definition from v1 to v2

##### **Option 1**: Using `drizzle-kit pull`

In new version `drizzle-kit pull` supports pulling `relations.ts` file in a new syntax:

##### Step 1

<Npx>
drizzle-kit pull
</Npx>

#### Step 2 

Transfer generated relations code from `drizzle/relations.ts` to the file you are using to specify your relations 
```plaintext {4-5}
 ├ 📂 drizzle
 │ ├ 📂 meta
 │ ├ 📜 migration.sql
 │ ├ 📜 relations.ts ────────┐
 │ └ 📜 schema.ts            |
 ├ 📂 src                    │ 
 │ ├ 📂 db                   │
 │ │ ├ 📜 relations.ts <─────┘
 │ │ └ 📜 schema.ts 
 │ └ 📜 index.ts         
 └ …
```

<Callout>
`drizzle/relations.ts` includes an import of all tables from `drizzle/schema.ts`, which looks like this:
```ts
import * as schema from './schema'
```

You may need to change this import to a file where ALL your schema tables are located. 

If there are multiple schema files, you can do the following:
```ts
import * as schema1 from './schema1'
import * as schema2 from './schema2'
...
```
</Callout>

#### Step 3

Change drizzle database instance creation and provide `relations` object instead of `schema`

<Callout title='Before'>
```ts
import * as schema from './schema'
import { drizzle } from 'drizzle-orm/...'

const db = drizzle('<url>', { schema })
```
</Callout>

<Callout title='After'>
```ts
// should be imported from a file in Step 2
import { relations } from './relations'
import { drizzle } from 'drizzle-orm/...'

const db = drizzle('<url>', { relations })
```
</Callout>

<Callout>
If you had MySQL dialect, you can remove `mode` from `drizzle()` as long as it's not needed in version 2
</Callout>

##### **Option 2**: Manual migration

If you want to migrate manually, you can check our [Drizzle Relations section](/docs/sqlite/relations) for the complete API reference and examples of one-to-one, one-to-many, and many-to-many relations.

#### How to migrate queries from v1 to v2

##### Migrate `where` statements

You can check our [Select Filters docs](/docs/sqlite/rqb#select-filters) to see examples and a complete API reference.

With the new syntax, you can use `AND`, `OR`, `NOT`, and `RAW`, plus all the filtering operators that 
were previously available in Relations v1.

**Examples**
<CodeTabs items={["simple eq", "using AND", "using OR", "using NOT", "complex example using RAW"]}>
<CodeTab>
```ts
const response = await db.query.users.findMany({
  where: {
    age: 15,
  },
});
```
```sql {8}
select
  "d0"."id" as "id",
  "d0"."name" as "name",
  "d0"."age" as "age"
from
  "users" as "d0"
where
  "d0"."age" = 15
```
</CodeTab>
<CodeTab>
```ts
const response = await db.query.users.findMany({
  where: {
    age: 15,
    name: 'John'
  },
});
```
```sql {9-10}
select
  "d0"."id" as "id",
  "d0"."name" as "name",
  "d0"."age" as "age"
from
  "users" as "d0"
where
  (
    ("d0"."age" = 15)
    and ("d0"."name" = 'John')
  )
```
</CodeTab>
<CodeTab>
```ts
const response = await db.query.users.findMany({
  where: {
    OR: [
      {
        id: {
          gt: 10,
        },
      },
      {
        name: {
          like: "John%",
        },
      },
    ],
  },
});
```
```sql {9-10}
select
  "d0"."id" as "id",
  "d0"."name" as "name",
  "d0"."age" as "age"
from
  "users" as "d0"
where
  (
    ("d0"."id" > 10)
    or ("d0"."name" like 'John%')
  )
```
</CodeTab>
<CodeTab>
```ts
const response = await db.query.users.findMany({
  where: {
    NOT: {
      id: {
        gt: 10,
      },
    },
    name: {
      like: "John%",
    },
  },
});
```
```sql {9-10}
select
  "d0"."id" as "id",
  "d0"."name" as "name",
  "d0"."age" as "age"
from
  "users" as "d0"
where
  (
    (not ("d0"."id" > 10))
    and ("d0"."name" like 'John%')
  )
```
</CodeTab>
<CodeTab>
```ts
// schema.ts
import { integer, sqliteTable, text } from "drizzle-orm/sqlite-core";
import { sql } from "drizzle-orm";

export const users = sqliteTable("users", {
  id: integer().primaryKey(),
  name: text(),
  email: text().notNull(),
  age: integer(),
  createdAt: text("created_at"),
  lastLogin: text("last_login"),
  subscriptionEnd: text("subscription_end"),
  lastActivity: text("last_activity"),
  preferences: text({ mode: "json" }), // JSON column for user settings/preferences
  interests: text(),                   // Comma-separated user interests
});
```
```ts
const response = await db.query.users.findMany({
  where: {
    AND: [
      {
        OR: [
          { RAW: (table) => sql`LOWER(${table.name}) LIKE 'john%'` },
          { name: { like: "jane%" } },
        ],
      },
      { RAW: (table) => sql`${table.age} BETWEEN 25 AND 35` },
    ],
  },
});
```
```sql
SELECT
	"d0"."id" AS "id",
	"d0"."name" AS "name",
	"d0"."email" AS "email",
	"d0"."age" AS "age",
	"d0"."created_at" AS "createdAt",
	"d0"."last_login" AS "lastLogin",
	"d0"."subscription_end" AS "subscriptionEnd",
	"d0"."last_activity" AS "lastActivity",
	"d0"."preferences" AS "preferences",
	"d0"."interests" AS "interests"
FROM
	"users" AS "d0"
WHERE
	(
		(
			(
				(LOWER("d0"."name") LIKE 'john%')
				OR ("d0"."name" LIKE 'jane%')
			)
		)
		AND ("d0"."age" BETWEEN 25 AND 35)
	)
```
</CodeTab>
</CodeTabs>

##### Migrate `orderBy` statements

Order by was simplified to a single object, where you specify the column and the sort direction (`asc` or `desc`)

<Callout title="❌ v1">
```ts
const response = db._query.users.findMany({
  orderBy: (users, { asc }) => [asc(users.id)],
});
```
</Callout>

<Callout title="✅ v2">
```ts
const response = db.query.users.findMany({
  orderBy: { id: "asc" },
});
```
</Callout>

##### Migrate `many-to-many` queries

Relational Queries v1 had a very complex way of managing many-to-many queries.
You had to use junction tables to query through them explicitly, and then map those tables out, like this:

```ts
const response = await db.query.users.findMany({
  with: {
    usersToGroups: {
      columns: {},
      with: {
        group: true,
      },
    },
  },
});
```

After upgrading to Relational Queries v2, your many-to-many relation will look like this:

```ts
import * as schema from './schema';
import { defineRelations } from 'drizzle-orm';

export const relations = defineRelations(schema, (r) => ({
  users: {
    groups: r.many.groups({
      from: r.users.id.through(r.usersToGroups.userId),
      to: r.groups.id.through(r.usersToGroups.groupId),
    }),
  },
  groups: {
    participants: r.many.users(),
  },
}));
```

And when you migrate your query, it will become this:

```ts
// Query example
const response = await db.query.users.findMany({
  with: {
    groups: true,
  },
});
```

### Internal changes

1. Every `drizzle` database, `session`, `migrator` and `transaction` instance updated with new generic arguments for RQB v2 queries

<Callout collapsed='Examples'>
**migrator**
<Callout type='error' title='before'>
```ts
export function migrate<
  TSchema extends Record<string, unknown>
>(
	db: BetterSQLite3Database<TSchema>,
	config: MigrationConfig,
) {
	...
}
```
</Callout>
<Callout title='now'>
```ts {3,5}
export function migrate<
  TSchema extends Record<string, unknown>,
  TRelations extends AnyRelations
>(
	db: BetterSQLite3Database<TSchema, TRelations>, // SQLiteBunDatabase, NodeSQLiteDatabase, DrizzleSqliteDODatabase, ...
	config: MigrationConfig,
) {
	...
}
```
</Callout>
**session**
<Callout type='error' title='before'>
```ts
export class BetterSQLiteSession<
	TFullSchema extends Record<string, unknown>,
	TSchema extends TablesRelationalConfig,
> extends SQLiteSession<'sync', RunResult, TFullSchema, TSchema>
```
</Callout>
<Callout title='now'>
```ts {3}
export class BetterSQLiteSession< // SQLiteBunSession, NodeSQLiteSession, ...
	TFullSchema extends Record<string, unknown>,
	TRelations extends AnyRelations,
	TSchema extends V1.TablesRelationalConfig,
> extends SQLiteSession<'sync', RunResult, TFullSchema, TRelations, TSchema>
```
</Callout>
**transaction**
<Callout type='error' title='before'>
```ts
export class BetterSQLiteTransaction<
	TFullSchema extends Record<string, unknown>,
	TSchema extends TablesRelationalConfig,
> extends SQLiteTransaction<'sync', RunResult, TFullSchema, TSchema>
```
</Callout>
<Callout title='now'>
```ts {3}
export class BetterSQLiteTransaction< // BunSQLiteTransaction, NodeSQLiteTransaction, ...
	TFullSchema extends Record<string, unknown>,
	TRelations extends AnyRelations,
	TSchema extends V1.TablesRelationalConfig,
> extends SQLiteTransaction<'sync', RunResult, TFullSchema, TRelations, TSchema>
```
</Callout>
**driver**
<Callout type='error' title='before'>
```ts
export class BetterSQLite3Database<
  TSchema extends Record<string, unknown> = Record<string, never>
> extends BaseSQLiteDatabase<'sync', RunResult, TSchema>
```
</Callout>
<Callout title='now'>
```ts {3}
export class BetterSQLite3Database<
	TSchema extends Record<string, unknown> = Record<string, never>,
	TRelations extends AnyRelations = EmptyRelations,
> extends BaseSQLiteDatabase<'sync', RunResult, TSchema, TRelations>
```
</Callout>
</Callout>

2. Updated `DrizzleConfig` generic with `TRelations` argument and `relations: TRelations` field

<Callout collapsed='Examples'>
<Callout type='error' title='before'>
```ts
export interface DrizzleConfig<
  TSchema extends Record<string, unknown> = Record<string, never>
> {
  logger?: boolean | Logger;
  schema?: TSchema;
  casing?: Casing;
}
```
</Callout>

<Callout title='now'>
```ts {2,5}
export interface DrizzleConfig<
	TRelationConfigs extends AnyRelations = EmptyRelations,
> {
	logger?: boolean | Logger | undefined;
	relations?: TRelationConfigs | undefined;
	cache?: Cache | undefined;
	jit?: boolean | undefined;
}
```
</Callout>
</Callout>

3. The following entities have been removed from `drizzle-orm` and `drizzle-orm/relations`. The original imports now 
include new types used by Relational Queries v2, so make sure to update your imports if you intend to use the older types:

<Callout collapsed='A list of all removed entities'>
- `Relations`
- `TableRelationsKeysOnly`
- `ExtractTableRelationsFromSchema`
- `ExtractRelationsFromTableExtraConfigSchema`
- `getOperators`
- `FindTableByDBName`
- `RelationalSchemaConfig`
- `RelationConfig`
- `extractTablesRelationalConfig`
- `relations`
- `createOne`
- `createMany`
- `NormalizedRelation`
- `normalizeRelation`
- `createTableRelationsHelpers`
- `TableRelationsHelpers`
</Callout>

4. In the same manner, `${dialect}-core/query-builders/query` files were updated with RQB v2's alternatives

<Callout collapsed='Examples'>
```ts
import { RelationalQueryBuilder, SQLiteRelationalQuery } from 'drizzle-orm/sqlite-core/query-builders/query';
```
</Callout>


Source: https://orm.drizzle.team/docs/sqlite/relations

import Tab from '@mdx/Tab.astro';
import Tabs from '@mdx/Tabs.astro';
import IsSupportedChipGroup from '@mdx/IsSupportedChipGroup.astro';
import Callout from '@mdx/Callout.astro';
import Section from '@mdx/Section.astro';
import Prerequisites from "@mdx/Prerequisites.astro";
import CodeTab from '@mdx/CodeTab.astro';
import CodeTabs from '@mdx/CodeTabs.astro';
import Npm from '@mdx/Npm.astro';

# Drizzle relations

<Npm>
 drizzle-orm@rc
 drizzle-kit@rc -D
</Npm>

<br/>

<Prerequisites>  
  - **Relations Fundamentals** - get familiar with the concepts of foreign key constraints, soft relations, database normalization, etc - [read here](/docs/sqlite/relations-schema-declaration)
  - **Declare schema** - get familiar with how to define drizzle schemas - [read here](/docs/sqlite/sql-schema-declaration)
  - **Database connection** - get familiar with how to connect to database using drizzle - [read here](/docs/sqlite/get-started-sqlite)
</Prerequisites>

The sole purpose of Drizzle relations is to let you query your relational data in the most simple and concise way:

<CodeTabs items={["Relational queries", "Select with joins"]}>
<Section>
```ts
import { drizzle } from 'drizzle-orm/...';
import { defineRelations } from 'drizzle-orm';
import * as p from 'drizzle-orm/sqlite-core';

export const users = p.sqliteTable('users', {
	id: p.integer().primaryKey(),
	name: p.text().notNull()
});

export const posts = p.sqliteTable('posts', {
	id: p.integer().primaryKey(),
	content: p.text().notNull(),
	ownerId: p.integer('owner_id'),
});

const relations = defineRelations({ users, posts }, (r) => ({
	posts: {
		author: r.one.users({
			from: r.posts.ownerId,
			to: r.users.id,
		}),
	}
}))

const db = drizzle(process.env.DB_URL, { relations });

const result = await db.query.posts.findMany({
  with: {
    author: true,
  },
});
```
```ts
[{
  id: 10,
  content: "My first post!",
  ownerId: 14,
  author: {
    id: 1,
    name: "Alex"
  }
}]
```
</Section>
<Section>
```ts
import { drizzle } from 'drizzle-orm/...';
import { eq } from 'drizzle-orm';
import { posts, users } from './schema';

const db = drizzle(process.env.DB_URL);

const res = await db.select()
                    .from(posts)
                    .leftJoin(users, eq(posts.ownerId, users.id))
                    .orderBy(posts.id)

const mappedResult = ...
```
</Section>
</CodeTabs>

### `one()`
Here is a list of all fields available for `.one()` in drizzle relations

```ts {3-11}
const relations = defineRelations({ users, posts }, (r) => ({
	posts: {
		author: r.one.users({
			from: r.posts.ownerId,
			to: r.users.id,
			optional: false,
      alias: 'custom_name',
			where: {
				verified: true,
			}
		}),
	}
}))
```

- `author` key is a custom key that appears in the `posts` object when using Drizzle relational queries.
- `r.one.users` defines that `author` will be a single object from the `users` table rather than an array of objects.
- `from: r.posts.ownerId` specifies the table from which we are establishing a soft relation. 
In this case, the relation starts from the `ownerId` column in the `posts` table.
- `to: r.users.id` specifies the table to which we are establishing a soft relation. 
In this case, the relation points to the `id` column in the `users` table.
- `optional: false` at the type level makes the `author` key in the posts object `required`. 
This should be used when you are certain that this specific entity will always exist.
- `alias` is used to add a specific alias to relationships between tables. If you have multiple identical relationships between two tables, you should 
differentiate them using `alias`
- `where` condition can be used for polymorphic relations. It fetches relations based on a `where` statement.
For example, in the case above, only `verified authors` will be retrieved. Learn more about polymorphic relations [here](/docs/sqlite/relations-schema-declaration#polymorphic-relations).

### `many()`

Here is a list of all fields available for `.many()` in drizzle relations

```ts {3-10}
const relations = defineRelations({ users, posts }, (r) => ({
	users: {
		feed: r.many.posts({
			from: r.users.id,
			to: r.posts.ownerId,
			alias: 'custom_name',
			where: {
				approved: true,
			}
		}),
	}
}))
```

- `feed` key is a custom key that appears in the `users` object when using Drizzle relational queries.
- `r.many.posts` defines that `feed` will be an array of objects from the `posts` table rather than just an object
- `from: r.users.id` specifies the table from which we are establishing a soft relation. 
In this case, the relation starts from the `id` column in the `users` table.
- `to: r.posts.ownerId` specifies the table to which we are establishing a soft relation. 
In this case, the relation points to the `ownerId` column in the `posts` table.
- `alias` is used to add a specific alias to relationships between tables. If you have multiple identical relationships between two tables, you should 
differentiate them using `alias`
- `where` condition can be used for polymorphic relations. It fetches relations based on a `where` statement.
For example, in the case above, only `approved posts` will be retrieved. Learn more about polymorphic relations [here](/docs/sqlite/relations-schema-declaration#polymorphic-relations).

## ---

### One-to-one
Drizzle ORM provides you an API to define `one-to-one` relations between tables with the `defineRelations` function.

An example of a `one-to-one` relation between users and users, where a user can invite another (this example uses a self reference):

```typescript copy {10-17}
import { sqliteTable, text, integer } from 'drizzle-orm/sqlite-core';
import { defineRelations } from 'drizzle-orm';

export const users = sqliteTable('users', {
	id: integer().primaryKey(),
	name: text(),
	invitedBy: integer('invited_by'),
});

export const relations = defineRelations({ users }, (r) => ({
	users: {
		invitee: r.one.users({
			from: r.users.invitedBy,
			to: r.users.id,
		})
	}
}));
```

Another example would be a user having a profile information stored in separate table. In this case, because the foreign key is stored in the "profile_info" table, the user relation have neither fields or references. This tells Typescript that `user.profileInfo` is nullable:

```typescript copy {15-22}
import { sqliteTable, text, integer } from 'drizzle-orm/sqlite-core';
import { defineRelations } from 'drizzle-orm';

export const users = sqliteTable('users', {
	id: integer().primaryKey(),
	name: text(),
});

export const profileInfo = sqliteTable('profile_info', {
	id: integer().primaryKey({ autoIncrement: true }),
	userId: integer('user_id').references(() => users.id),
	metadata: text({ mode: 'json' }),
});

export const relations = defineRelations({ users, profileInfo }, (r) => ({
	users: {
		profileInfo: r.one.profileInfo({
			from: r.users.id,
			to: r.profileInfo.userId,
		})
	}
}));

const user = await db.query.users.findFirst({ with: { profileInfo: true } });
//____^? type { id: number, name: string | null, profileInfo: { ... } | null  }
```

### One-to-many
Drizzle ORM provides you an API to define `one-to-many` relations between tables with `defineRelations` function. 

Example of `one-to-many` relation between users and posts they've written:

```typescript copy {15-25}
import { sqliteTable, text, integer } from 'drizzle-orm/sqlite-core';
import { defineRelations } from 'drizzle-orm';

export const users = sqliteTable('users', {
	id: integer('id').primaryKey(),
	name: text('name'),
});

export const posts = sqliteTable('posts', {
	id: integer('id').primaryKey(),
	content: text('content'),
	authorId: integer('author_id'),
});

export const relations = defineRelations({ users, posts }, (r) => ({
  posts: {
    author: r.one.users({
      from: r.posts.authorId,
      to: r.users.id,
    }),
  },
  users: {
    posts: r.many.posts(),
  },
}));
```

Now lets add comments to the posts:
```typescript copy {9-14,22,27-32}
...

export const posts = sqliteTable('posts', {
	id: integer('id').primaryKey(),
	content: text('content'),
	authorId: integer('author_id'),
});

export const comments = sqliteTable("comments", {
  id: integer().primaryKey(),
  text: text(),
  authorId: integer("author_id"),
  postId: integer("post_id"),
});

export const relations = defineRelations({ users, posts, comments }, (r) => ({
  posts: {
    author: r.one.users({
      from: r.posts.authorId,
      to: r.users.id,
    }),
    comments: r.many.comments(),
  },
  users: {
    posts: r.many.posts(),
  },
  comments: {
    post: r.one.posts({
      from: r.comments.postId,
      to: r.posts.id,
    }),
  },
}));
```


### Many-to-many
Drizzle ORM provides you an API to define `many-to-many` relations between tables through so called `junction` or `join` tables,
they have to be explicitly defined and store associations between related tables.  

Example of `many-to-many` relation between users and groups we are using `through` to bypass junction table selection and directly select many `groups` for each `user`.
```typescript copy {27-39}
import { defineRelations } from 'drizzle-orm';
import { integer, sqliteTable, primaryKey, text } from 'drizzle-orm/sqlite-core';

export const users = sqliteTable('users', {
  id: integer().primaryKey(),
  name: text(),
});

export const groups = sqliteTable('groups', {
  id: integer().primaryKey(),
  name: text(),
});

export const usersToGroups = sqliteTable(
  'users_to_groups',
  {
    userId: integer('user_id')
      .notNull()
      .references(() => users.id),
    groupId: integer('group_id')
      .notNull()
      .references(() => groups.id),
  },
  (t) => [primaryKey({ columns: [t.userId, t.groupId] })],
);

export const relations = defineRelations({ users, groups, usersToGroups },
  (r) => ({
    users: {
      groups: r.many.groups({
        from: r.users.id.through(r.usersToGroups.userId),
        to: r.groups.id.through(r.usersToGroups.groupId),
      }),
    },
    groups: {
      participants: r.many.users(),
    },
  })
);
```

**Query example:**
```ts
const res = await db.query.users.findMany({
  with: { 
    groups: true 
  },
});

// response type
type Response = {
  id: number;
  name: string | null;
  groups: {
    id: number;
    name: string | null;
  }[];
}[];
```

### Predefined filters

Predefined `where` statements in Drizzle's relation definitions are a type of polymorphic relations implementation, but it's not fully it. Essentially, they allow you to
connect tables not only by selecting specific columns but also through custom `where` statements. Let's look at some examples:

We can define a relation between `groups` and `users` so that when querying group's users, we only retrieve those whose `verified` column is set to `true`
<CodeTabs items={["Relations", "Schema"]}>
<Section>
```ts
import { defineRelations } from "drizzle-orm";
import * as schema from './schema';

export const relations = defineRelations(schema,(r) => ({
    groups: {
      verifiedUsers: r.many.users({
        from: r.groups.id.through(r.usersToGroups.groupId),
        to: r.users.id.through(r.usersToGroups.userId),
        where: {
          verified: true,
        },
      }),
    },
  })
);

...

await db.query.groups.findMany({
    with: {
      verifiedUsers: true,
    },
});
```
</Section>
<Section>
```ts
import * as p from "drizzle-orm/sqlite-core";

export const users = p.sqliteTable("users", {
  id: p.integer().primaryKey(),
  name: p.text().notNull(),
  verified: p.integer({ mode: 'boolean' }).notNull(),
});

export const groups = p.sqliteTable("groups", {
  id: p.integer().primaryKey(),
  title: p.text().notNull(),
});

export const usersToGroups = p.sqliteTable(
  "users_to_groups",
  {
    userId: p
      .integer("user_id")
      .notNull()
      .references(() => users.id, { onDelete: "cascade" }),
    groupId: p
      .integer("group_id")
      .notNull()
      .references(() => groups.id, { onDelete: "cascade" }),
  },
  (t) => [p.primaryKey({ columns: [t.groupId, t.userId] })]
);
```
</Section>
</CodeTabs>

<Callout type='warning'>
You can only specify filters on the target (to) table. So in this example, the where clause will only include columns from the `users` table since we are establishing a relation **TO** users

```ts {7}
export const relations = defineRelations(schema,(r) => ({
    groups: {
      verifiedUsers: r.many.users({
        from: r.groups.id.through(r.usersToGroups.groupId),
        to: r.users.id.through(r.usersToGroups.userId),
        where: {
          verified: true,
        },
      }),
    },
  })
);
```
</Callout>

## ---

### Relations Parts

In a case you need to separate relations config into several parts you can use `defineRelationsPart` helpers

```ts
import { defineRelations, defineRelationsPart } from 'drizzle-orm';
import * as schema from "./schema";

export const relations = defineRelations(schema, (r) => ({
  users: {
    invitee: r.one.users({
      from: r.users.invitedBy,
      to: r.users.id,
    }),
    posts: r.many.posts(),
  }
}));

export const part = defineRelationsPart(schema, (r) => ({
  posts: {
    author: r.one.users({
      from: r.posts.authorId,
      to: r.users.id,
    }),
  }
}));
```

and then you can provide it to the db instance

```ts
const db = drizzle(process.env.DB_URL, { relations: { ...relations, ...part } })
```

<Callout type='warning'>
There are a few rules you would need to follow to make sure it `defineRelationsParts` works as expected

**Rule 1**: If you specify reltions with parts, when passing it to drizzle db function you would need to specify it in the right order(main relations goes first)
```ts
// ✅
const db = drizzle(process.env.DB_URL, { relations: { ...relations, ...part } })

// ❌
const db = drizzle(process.env.DB_URL, { relations: { ...part, ...relations } })
```

<Callout collapsed="Why it's important?">
Even if there will be no type or runtime error, this is how "..." works with objects. As long as main relation 
recursively infer all tables names, so it can be available in autocomplete. Here is an example:

```ts
export const relations = defineRelations(schema, (r) => ({
  users: {
    invitee: r.one.users({
      from: r.users.invitedBy,
      to: r.users.id,
    }),
    posts: r.many.posts(),
  }
}));

export const part = defineRelationsPart(schema, (r) => ({
  posts: {
    author: r.one.users({
      from: r.posts.authorId,
      to: r.users.id,
    }),
  }
}));
```

Here `relations` and `part` can be represented and this object:
```json
// relations
{
  "users": {"invitee": {...}, "posts": {...}},
  // added here, so all tables from schema will exist in autocomplete
  "posts": {}
}

// part
{
  "posts": {"author": {...}}
}
```

Having `{ ...relations, ...part }` will result in 
```json
{
  "users": {"invitee": {...}, "posts": {...}},
  "posts": {"author": {...}}
}
```

and having `{ ...relations, ...part }` will result in
```json
{
  "users": {"invitee": {...}, "posts": {...}},
  // As you can see in the final object, posts relations information will be lost
  "posts": {}
}
```

</Callout>

**Rule 2**: You should have min relations, so drizzle can infer all of the table for autocomplete. If you want to have only parts, then 
one of your parts should be empty, like this:

```ts
export const mainPart = defineRelationsPart(schema);
```

In this case, all tables will be inferred correctly, and you'll have complete information about your schema
</Callout>

## ---

### Performance

When working with relations in Drizzle ORM, especially in applications with 
significant data or complex queries, optimizing database performance is crucial.  
Indexes play a vital role in speeding up data retrieval, particularly when querying 
related data. This section outlines recommended indexing strategies for each type 
of relationship defined using Drizzle ORM.

##### One-to-one Relationships

In a one-to-one relationship, like the "user invites user" example or the
"user has profile info" example, the key performance consideration is efficient joining 
of the related tables.

<Callout>
For optimal performance in one-to-one relationships, you should create an index 
on the foreign key column in the table that is being referenced 
(the "target" table in the relation).
</Callout>

<Callout collapsed='Why it is important'>
When you query data with related one-to-one information, Drizzle performs a JOIN operation. An index on the foreign key column allows the database to quickly 
locate the related row in the target table, significantly speeding up the join process.
</Callout>

**Example:**
```typescript
import * as p from 'drizzle-orm/sqlite-core';
import { defineRelations } from 'drizzle-orm';

export const users = p.sqliteTable('users', {
	id: p.integer().primaryKey(),
	name: p.text(),
});

export const profileInfo = p.sqliteTable('profile_info', {
	id: p.integer().primaryKey(),
	userId: p.integer('user_id').references(() => users.id),
	metadata: p.text({ mode: 'json' }),
});

export const relations = defineRelations({ users, profileInfo }, (r) => ({
	users: {
		profileInfo: r.one.profileInfo({
			from: r.users.id,
			to: r.profileInfo.userId,
		})
	}
}));
```

To optimize queries fetching user data along with their profile information, 
you should create an index on the `userId` column in the `profile_info` table.

```typescript {13-15}
import * as p from 'drizzle-orm/sqlite-core';
import { defineRelations } from 'drizzle-orm';

export const users = p.sqliteTable('users', {
	id: p.integer().primaryKey(),
	name: p.text(),
});

export const profileInfo = p.sqliteTable('profile_info', {
	id: p.integer().primaryKey(),
	userId: p.integer('user_id').references(() => users.id),
	metadata: p.text({ mode: 'json' }),
}, (table) => [
  p.index('profile_info_user_id_idx').on(table.userId)
]);

export const relations = defineRelations({ users, profileInfo }, (r) => ({
	users: {
		profileInfo: r.one.profileInfo({
			from: r.users.id,
			to: r.profileInfo.userId,
		})
	}
}));
```
```sql
CREATE INDEX `profile_info_user_id_idx` ON `profile_info` (`user_id`);
```

#### One-to-many Relationships

Similar to one-to-one relationships, one-to-many relations benefit significantly 
from indexing to optimize join operations. Consider the "users and posts" example where one user can have many posts.

<Callout>
For one-to-many relationships, create an index on the foreign key column in the table that represents the "many" side of the relationship (the table with the foreign key referencing the "one" side).
</Callout>

<Callout collapsed='Why it is important'>
When you fetch a user with their posts or posts with their authors, joins are performed.
Indexing the foreign key (`authorId` in `posts` table) allows the database to efficiently 
retrieve all posts associated with a given user or quickly find the author of a post.
</Callout>

**Example:**
```typescript
import * as p from "drizzle-orm/sqlite-core";
import { defineRelations } from 'drizzle-orm';

export const users = p.sqliteTable('users', {
	id: p.integer().primaryKey(),
	name: p.text(),
});

export const posts = p.sqliteTable('posts', {
	id: p.integer().primaryKey(),
	content: p.text(),
	authorId: p.integer('author_id'),
});

export const relations = defineRelations({ users, posts }, (r) => ({
  posts: {
    author: r.one.users({
      from: r.posts.authorId,
      to: r.users.id,
    }),
  },
  users: {
    posts: r.many.posts(),
  },
}));
```

To optimize queries involving users and their posts, create an index on the `authorId` column in the `posts` table.

```typescript {13-15}
import * as p from "drizzle-orm/sqlite-core";
import { defineRelations } from 'drizzle-orm';

export const users = p.sqliteTable('users', {
	id: p.integer().primaryKey(),
	name: p.text(),
});

export const posts = p.sqliteTable('posts', {
	id: p.integer().primaryKey(),
	content: p.text(),
	authorId: p.integer('author_id'),
}, (t) => [
  p.index('posts_author_id_idx').on(t.authorId)
]);

export const relations = defineRelations({ users, posts }, (r) => ({
  posts: {
    author: r.one.users({
      from: r.posts.authorId,
      to: r.users.id,
    }),
  },
  users: {
    posts: r.many.posts(),
  },
}));
```
```sql
CREATE INDEX `posts_author_id_idx` ON `posts` (`author_id`);
```

#### Many-to-many Relationships

Many-to-many relationships, implemented using junction tables, require a slightly 
more nuanced indexing strategy to ensure optimal query performance. 
Consider the "users and groups" example with the `usersToGroups` junction table.

<Callout>
For many-to-many relationships, it is generally recommended to create the following 
indexes on the junction table:
1.  **Index on each foreign key column individually:** This optimizes queries that 
filter or join based on a single side of the relationship 
(e.g., finding all groups for a user OR all users in a group).
2.  **Composite index on both foreign key columns together:** This is crucial for 
efficiently resolving the many-to-many relationship itself. It speeds up queries that need to find the connections between both entities.
</Callout>

<Callout collapsed='Why it is important'>
When querying many-to-many relations, especially when using `through` in Drizzle ORM, the database needs to efficiently navigate the junction table.

- Indexes on individual foreign key columns (`userId`, `groupId` in `usersToGroups`) help when you are querying from one side to find the other (e.g., "find groups for a user").
- The composite index on `(userId, groupId)` in `usersToGroups` is particularly important for quickly finding all relationships defined in the junction table. This is used when Drizzle ORM resolves the `many-to-many` relation to fetch related entities.
</Callout>

**Example:**

In the "users and groups" example, the `usersToGroups` junction table connects `users` and `groups`.

```typescript
import { defineRelations } from 'drizzle-orm';
import * as p from 'drizzle-orm/sqlite-core';

export const users = p.sqliteTable('users', {
  id: p.integer().primaryKey(),
  name: p.text(),
});

export const groups = p.sqliteTable('groups', {
  id: p.integer().primaryKey(),
  name: p.text(),
});

export const usersToGroups = p.sqliteTable(
  'users_to_groups',
  {
    userId: p.integer('user_id')
      .notNull()
      .references(() => users.id),
    groupId: p.integer('group_id')
      .notNull()
      .references(() => groups.id),
  },
  (t) => [p.primaryKey({ columns: [t.userId, t.groupId] })],
);

export const relations = defineRelations({ users, groups, usersToGroups },
  (r) => ({
    users: {
      groups: r.many.groups({
        from: r.users.id.through(r.usersToGroups.userId),
        to: r.groups.id.through(r.usersToGroups.groupId),
      }),
    },
    groups: {
      participants: r.many.users(),
    },
  })
);
```

To optimize queries for users and groups, create indexes on `usersToGroups` table as follows:

```typescript {26-28}
import { defineRelations } from 'drizzle-orm';
import * as p from 'drizzle-orm/sqlite-core';

export const users = p.sqliteTable('users', {
  id: p.integer().primaryKey(),
  name: p.text(),
});

export const groups = p.sqliteTable('groups', {
  id: p.integer().primaryKey(),
  name: p.text(),
});

export const usersToGroups = p.sqliteTable(
  'users_to_groups',
  {
    userId: p.integer('user_id')
      .notNull()
      .references(() => users.id),
    groupId: p.integer('group_id')
      .notNull()
      .references(() => groups.id),
  },
  (t) => [
    p.primaryKey({ columns: [t.userId, t.groupId] }),
    p.index('users_to_groups_user_id_idx').on(t.userId),
    p.index('users_to_groups_group_id_idx').on(t.groupId),
    p.index('users_to_groups_composite_idx').on(t.userId, t.groupId),
  ],
);

export const relations = defineRelations({ users, groups, usersToGroups },
  (r) => ({
    users: {
      groups: r.many.groups({
        from: r.users.id.through(r.usersToGroups.userId),
        to: r.groups.id.through(r.usersToGroups.groupId),
      }),
    },
    groups: {
      participants: r.many.users(),
    },
  })
);
```
```sql
CREATE INDEX `users_to_groups_user_id_idx` ON `users_to_groups` (`user_id`);
CREATE INDEX `users_to_groups_group_id_idx` ON `users_to_groups` (`group_id`);
CREATE INDEX `users_to_groups_composite_idx` ON `users_to_groups` (`user_id`,`group_id`);
```

By applying these indexing strategies, you can significantly improve the performance of your Drizzle ORM applications when working with relational data, especially as your data volume grows and your queries become more complex. Remember to choose the indexes that best suit your specific query patterns and application needs.

## ---

### Foreign keys

You might've noticed that `relations` look similar to foreign keys — they even have a `references` property. So what's the difference?

While foreign keys serve a similar purpose, defining relations between tables, they work on a different level compared to `relations`.

Foreign keys are a database level constraint, they are checked on every `insert`/`update`/`delete` operation and throw an error if a constraint is violated.
On the other hand, `relations` are a higher level abstraction, they are used to define relations between tables on the application level only.
They do not affect the database schema in any way and do not create foreign keys implicitly.

What this means is `relations` and foreign keys can be used together, but they are not dependent on each other.
You can define `relations` without using foreign keys (and vice versa), which allows them to be used with databases that do not support foreign keys.

The following two examples will work exactly the same in terms of querying the data using Drizzle relational queries.

<CodeTabs items={["schema1.ts", "schema2.ts"]}>
<CodeTab>
```ts {15}
export const users = p.sqliteTable("users", {
  id: p.integer().primaryKey(),
  name: p.text(),
});

export const profileInfo = p.sqliteTable("profile_info", {
  id: p.integer().primaryKey(),
  userId: p.integer("user_id"),
  metadata: p.text({ mode: 'json' }),
});

export const relations = defineRelations({ users, profileInfo }, (r) => ({
  users: {
    profileInfo: r.one.profileInfo({
      from: r.users.id,
      to: r.profileInfo.userId,
    }),
  },
}));
```
</CodeTab>
<CodeTab>
```ts {15}
export const users = p.sqliteTable("users", {
  id: p.integer().primaryKey(),
  name: p.text(),
});

export const profileInfo = p.sqliteTable("profile_info", {
  id: p.integer().primaryKey(),
  userId: p.integer("user_id").references(() => users.id),
  metadata: p.text({ mode: 'json' }),
});

export const relations = defineRelations({ users, profileInfo }, (r) => ({
  users: {
    profileInfo: r.one.profileInfo({
      from: r.users.id,
      to: r.profileInfo.userId,
    }),
  },
}));
```
</CodeTab>
</CodeTabs>

### Disambiguating relations

Drizzle also provides the `alias` option as a way to disambiguate
relations when you define multiple of them between the same two tables. For
example, if you define a `posts` table that has the `author` and `reviewer`
relations.

```ts {19,22,29,34}
import { sqliteTable, integer, text } from 'drizzle-orm/sqlite-core';
import { defineRelations } from 'drizzle-orm';
 
export const users = sqliteTable('users', {
	id: integer().primaryKey(),
	name: text(),
});

export const posts = sqliteTable('posts', {
	id: integer().primaryKey(),
	content: text(),
	authorId: integer('author_id'),
	reviewerId: integer('reviewer_id'),
});
 
export const relations = defineRelations({ users, posts }, (r) => ({
  users: {
    posts: r.many.posts({
      alias: "author",
    }),
    reviewedPosts: r.many.posts({
      alias: "reviewer",
    }),
  },
  posts: {
    author: r.one.users({
      from: r.posts.authorId,
      to: r.users.id,
      alias: "author",
    }),
    reviewer: r.one.users({
      from: r.posts.authorId,
      to: r.users.id,
      alias: "reviewer",
    }),
  },
}));
```


Source: https://orm.drizzle.team/docs/sqlite/rqb

import Npm from '@mdx/Npm.astro';
import Callout from '@mdx/Callout.astro';
import CodeTabs from '@mdx/CodeTabs.astro';
import CodeTab from '@mdx/CodeTab.astro';
import Section from '@mdx/Section.astro';

# Drizzle Queries

Drizzle ORM is designed to be a thin typed layer on top of SQL. 
We truly believe we've designed the best way to operate an SQL database from TypeScript and it's time to make it better.  
  
Relational queries are meant to provide you with a great developer experience for querying 
nested relational data from an SQL database, avoiding multiple joins and complex data mappings.  

It is an extension to the existing schema definition and query builder. 
You can opt-in to use it based on your needs. 
We've made sure you have both the best-in-class developer experience and performance.  

<Callout type="info" title='Important'>
Inside relational queries, references to a table's columns must go through the callback parameter, not through the imported table object. 
This applies to every clause that accepts a callback — `orderBy`, `where`.`RAW`, `extras` and `subqueries inside extras`. 
The callback exposes the aliased table for the current query scope, which is required for correct SQL generation in nested or self-referential queries.

<Callout type="error" title='❌' collapsed="Example">
```ts
await db.query.posts.findMany({
  orderBy: sql`${posts.id} asc`, // <- ❌ direct table usage
  with: {
    comments: {
      orderBy: sql`${comments.id} desc`, // <- ❌ direct table usage
    },
  },
});
```
```ts
await db.query.users.findMany({
  where: {
    RAW: sql`LOWER(${users.name}) LIKE 'john%'`, // <- ❌ direct table usage
  },
});
```
```ts
await db.query.users.findMany({
  extras: {
    loweredName: sql<string>`lower(${users.name})`, // <- ❌ direct table usage
    totalPostsCount: db.$count(posts, eq(posts.authorId, users.id)),  // <- ❌ direct table usage
  },
});
```
</Callout>
<Callout type="default" title='✅' collapsed="Example">
```ts
await db.query.posts.findMany({
  orderBy: (t) => sql`${t.id} asc`, // <- ✅ callback used
  with: {
    comments: {
      orderBy: (t, { desc }) => desc(t.id), // <- ✅ callback used
    },
  },
});
```
```ts
await db.query.users.findMany({
  where: {
    RAW: (t) => sql`LOWER(${t.name}) LIKE 'john%'`, // <- ✅ callback used
  },
});
```
```ts
await db.query.users.findMany({
  extras: {
    loweredName: (t, { sql }) => sql<string>`lower(${t.name})`, // <- ✅ callback used
    totalPostsCount: (t) => db.$count(posts, eq(posts.authorId, t.id)), // <- ✅ callback used
  },
});
```
</Callout>
</Callout>

<br/>

<Callout type="info" emoji="ℹ️">
	`drizzle` import path depends on the **[database driver](/docs/sqlite/connect-overview)** you're using.
</Callout>
<CodeTabs items={["index.ts", "schema.ts", "relations.ts"]}>
	<CodeTab>
	```typescript copy
	import { relations } from "./relations";
	import { drizzle } from "drizzle-orm/...";

	const db = drizzle(process.env.DATABASE_URL, { relations });

	const result = await db.query.users.findMany({
	  with: {
	    posts: true,
	  },
	});
	```

	```ts
	[{
		id: 10,
		name: "Dan",
		posts: [
			{
				id: 1,
				content: "SQL is awesome",
				authorId: 10,
			},
			{
				id: 2,
				content: "But check relational queries",
				authorId: 10,
			}
		]
	}]
	```
	</CodeTab>

		```typescript copy
    import * as t from "drizzle-orm/sqlite-core";
    
    export const posts = t.sqliteTable("posts", {
      id: t.integer().primaryKey({ autoIncrement: true }),
      content: t.text().notNull(),
      authorId: t.integer("author_id").notNull(),
    });
    
    export const users = t.sqliteTable("users", {
      id: t.integer().primaryKey({ autoIncrement: true }),
      name: t.text().notNull(),
    });
	```

	```typescript copy
	import { defineRelations } from "drizzle-orm";
	import { posts, users } from "./schema";

	export const relations = defineRelations({ users, posts }, (r) => ({
      posts: {
        author: r.one.users({
          from: r.posts.authorId,
          to: r.users.id,
        }),
      },
      users: {
        posts: r.many.posts(),
      },
    }));
	```
</CodeTabs>

Relational queries are an extension to Drizzle's original **[query builder](/docs/sqlite/select)**.
You need to provide all `tables` and `relations` from your schema file/files upon `drizzle()` 
initialization and then just use the `db.query` API.
<Callout type="info" emoji="ℹ️">
	`drizzle` import path depends on the **[database driver](/docs/sqlite/connect-overview)** you're using.
</Callout>
<CodeTabs items={["index.ts", "schema.ts", "relations.ts"]}>
<CodeTab>
```ts
import { relations } from './relations';
import { drizzle } from 'drizzle-orm/...';

const db = drizzle(process.env.DATABASE_URL,{ relations });

await db.query.users.findMany(...);
```
</CodeTab>
```typescript copy
import { type AnySQLiteColumn, integer, sqliteTable, primaryKey, text } from 'drizzle-orm/sqlite-core';

export const users = sqliteTable('users', {
	id: integer().primaryKey({ autoIncrement: true }),
	name: text().notNull(),
	invitedBy: integer('invited_by').references((): AnySQLiteColumn => users.id),
});

export const groups = sqliteTable('groups', {
	id: integer().primaryKey({ autoIncrement: true }),
	name: text().notNull(),
	description: text(),
});

export const usersToGroups = sqliteTable('users_to_groups', {
	id: integer().primaryKey({ autoIncrement: true }),
	userId: integer('user_id').notNull().references(() => users.id),
	groupId: integer('group_id').notNull().references(() => groups.id),
}, (t) => [
	primaryKey({ columns: [t.userId, t.groupId] })
]);

export const posts = sqliteTable('posts', {
	id: integer().primaryKey({ autoIncrement: true }),
	content: text().notNull(),
	authorId: integer('author_id').references(() => users.id),
	createdAt: integer('created_at', { mode: 'timestamp' }).notNull(),
});

export const comments = sqliteTable('comments', {
	id: integer().primaryKey({ autoIncrement: true }),
	content: text().notNull(),
	creator: integer().references(() => users.id),
	postId: integer('post_id').references(() => posts.id),
	createdAt: integer('created_at', { mode: 'timestamp' }).notNull(),
});

export const commentLikes = sqliteTable('comment_likes', {
	id: integer().primaryKey({ autoIncrement: true }),
	creator: integer().references(() => users.id),
	commentId: integer('comment_id').references(() => comments.id),
	createdAt: integer('created_at', { mode: 'timestamp' }).notNull(),
});
```
```typescript copy
import { defineRelations } from 'drizzle-orm';
import * as schema from './schema';

export const relations = defineRelations(schema, (r) => ({
    users: {
      invitee: r.one.users({
        from: r.users.invitedBy,
        to: r.users.id,
      }),
      groups: r.many.groups({
        from: r.users.id.through(r.usersToGroups.userId),
        to: r.groups.id.through(r.usersToGroups.groupId),
      }),
      posts: r.many.posts(),
    },
    groups: {
      users: r.many.users(),
    },
    posts: {
      author: r.one.users({
        from: r.posts.authorId,
        to: r.users.id,
      }),
      comments: r.many.comments(),
    },
    comments: {
      post: r.one.posts({
        from: r.comments.postId,
        to: r.posts.id,
      }),
      author: r.one.users({
        from: r.comments.creator,
        to: r.users.id,
      }),
      likes: r.many.commentLikes(),
    },
    commentLikes: {
      comment: r.one.comments({
        from: r.commentLikes.commentId,
        to: r.comments.id,
      }),
      author: r.one.users({
        from: r.commentLikes.creator,
        to: r.users.id,
      }),
    },
  })
);
```
</CodeTabs>

Drizzle provides `.findMany()` and `.findFirst()` APIs.
### Find many
<Section>
```typescript copy
const users = await db.query.users.findMany();
```
```ts
// result type
const result: {
	id: number;
	name: string;
	verified: boolean;
	invitedBy: number | null;
}[];
```
</Section>

### Find first
<Callout>
  `.findFirst()` will add `limit 1` to the query.
</Callout>
<Section>
```typescript copy
const user = await db.query.users.findFirst();
```
```ts
// result type
const result: {
	id: number;
	name: string;
	verified: boolean;
	invitedBy: number | null;
};
```
</Section>

### Include relations

`With` operator lets you combine data from multiple related tables and properly aggregate results.

**Getting all posts with comments:**
```typescript copy
const posts = await db.query.posts.findMany({
	with: {
		comments: true,
	},
});
```

**Getting first post with comments:**
```typescript copy
const post = await db.query.posts.findFirst({
	with: {
		comments: true,
	},
});
```

You can chain nested with statements as much as necessary.  
For any nested `with` queries Drizzle will infer types using [Core Type API](/docs/sqlite/goodies#type-api).
  
**Get all users with posts. Each post should contain a list of comments:**
```typescript copy
const users = await db.query.users.findMany({
	with: {
		posts: {
			with: {
				comments: true,
			},
		},
	},
});
```

### Partial fields select
`columns` parameter lets you include or omit columns you want to get from the database.

<Callout type="info" emoji="ℹ️">
  Drizzle performs partial selects on the query level, no additional data is transferred from the database.

  Keep in mind that **a single SQL statement is outputted by Drizzle.**
</Callout>

**Get all posts with just `id`, `content` and include `comments`:**
```typescript copy
const posts = await db.query.posts.findMany({
	columns: {
		id: true,
		content: true,
	},
	with: {
		comments: true,
	}
});
```

**Get all posts without `content`:**
```typescript copy
const posts = await db.query.posts.findMany({
	columns: {
		content: false,
	},
});
```

<Callout type="info" emoji="ℹ️">
When both `true` and `false` select options are present, all `false` options are ignored.
</Callout>

If you include the `name` field and exclude the `id` field, `id` exclusion will be redundant, 
all fields apart from `name` would be excluded anyways.  
  
**Exclude and Include fields in the same query:**
<Section>
```typescript copy
const users = await db.query.users.findMany({
	columns: {
		name: true,
		id: false //ignored
	},
});
```
```ts
// result type
const users: {
	name: string;
};
```
</Section>

**Only include columns from nested relations:**
<Section>
```typescript copy
const res = await db.query.users.findMany({
	columns: {},
	with: {
		posts: true
	}
});
```
```ts
// result type
const res: {
	posts: {
		id: number,
		text: string
	}
}[];
```
</Section>

### Nested partial fields select
Just like with **[`partial select`](#partial-select)**, you can include or exclude columns of nested relations:
```typescript copy
const posts = await db.query.posts.findMany({
	columns: {
		id: true,
		content: true,
	},
	with: {
		comments: {
			columns: {
				authorId: false
			}
		}
	}
});
```

### Select filters
Just like in our SQL-like query builder, 
relational queries API lets you define filters and conditions with the list of our **[`operators`](/docs/sqlite/operators)**.  

You can either import them from `drizzle-orm` or use from the callback syntax:
<Section>
```typescript copy
const users = await db.query.users.findMany({
	where: {
		id: 1
	}
});
```
```sql {7}
select
  "d0"."id" as "id",
  "d0"."name" as "name"
from
  "users" as "d0"
where
  "d0"."id" = 1
```
</Section>

Find post with `id=1` and comments that were created before particular date:
```typescript copy
await db.query.posts.findMany({
  where: {
    id: 1,
  },
  with: {
    comments: {
      where: {
        createdAt: { lt: new Date() },
      },
    },
  },
});
```

**List of all filter operators**
```ts
where: {
    OR: [],
    AND: [],
    NOT: {},
    RAW: (table) => sql`${table.id} = 1`,

    // filter by relations
    [relation]: {},

	  // filter by columns
    [column]: {
      OR: [],
      AND: [],
      NOT: {},
      eq: 1,
      ne: 1,
      gt: 1,
      gte: 1,
      lt: 1,
      lte: 1,
      in: [1],
      notIn: [1],
      like: "",
      notLike: "",
      isNull: true,
      isNotNull: true,
    },
},
```

**Examples**
<CodeTabs items={["simple eq", "using AND", "using OR", "using NOT", "complex example using RAW"]}>
<CodeTab>
```ts
const response = await db.query.users.findMany({
  where: {
    age: 15,
  },
});
```
```sql {8}
select
  "d0"."id" as "id",
  "d0"."name" as "name",
  "d0"."age" as "age"
from
  "users" as "d0"
where
  "d0"."age" = 15
```
</CodeTab>
<CodeTab>
```ts
const response = await db.query.users.findMany({
  where: {
    age: 15,
    name: 'John'
  },
});
```
```sql {9-10}
select
  "d0"."id" as "id",
  "d0"."name" as "name",
  "d0"."age" as "age"
from
  "users" as "d0"
where
  (
    ("d0"."age" = 15)
    and ("d0"."name" = 'John')
  )
```
</CodeTab>
<CodeTab>
```ts
const response = await db.query.users.findMany({
  where: {
    OR: [
      {
        id: {
          gt: 10,
        },
      },
      {
        name: {
          like: "John%",
        },
      },
    ],
  },
});
```
```sql {9-10}
select
  "d0"."id" as "id",
  "d0"."name" as "name",
  "d0"."age" as "age"
from
  "users" as "d0"
where
  (
    ("d0"."id" > 10)
    or ("d0"."name" like 'John%')
  )
```
</CodeTab>
<CodeTab>
```ts
const response = await db.query.users.findMany({
  where: {
    NOT: {
      id: {
        gt: 10,
      },
    },
    name: {
      like: "John%",
    },
  },
});
```
```sql {9-10}
select
  "d0"."id" as "id",
  "d0"."name" as "name",
  "d0"."age" as "age"
from
  "users" as "d0"
where
  (
    (not ("d0"."id" > 10))
    and ("d0"."name" like 'John%')
  )
```
</CodeTab>
<CodeTab>
```ts
// schema.ts
import { integer, sqliteTable, text } from "drizzle-orm/sqlite-core";
import { sql } from "drizzle-orm";

export const users = sqliteTable("users", {
  id: integer().primaryKey(),
  name: text(),
  email: text().notNull(),
  age: integer(),
  createdAt: text("created_at"),
  lastLogin: text("last_login"),
  subscriptionEnd: text("subscription_end"),
  lastActivity: text("last_activity"),
  preferences: text("preferences", { mode: "json" }), // JSON column for user settings/preferences
  interests: text("interests"),                       // Comma-separated user interests
});
```
```ts
const response = await db.query.users.findMany({
  where: {
    AND: [
      {
        OR: [
          { RAW: (table) => sql`LOWER(${table.name}) LIKE 'john%'` },
          { name: { like: "jane%" } },
        ],
      },
      { RAW: (table) => sql`${table.age} BETWEEN 25 AND 35` },
    ],
  },
});
```
```sql
SELECT
	"d0"."id" AS "id",
	"d0"."name" AS "name",
	"d0"."email" AS "email",
	"d0"."age" AS "age",
	"d0"."created_at" AS "createdAt",
	"d0"."last_login" AS "lastLogin",
	"d0"."subscription_end" AS "subscriptionEnd",
	"d0"."last_activity" AS "lastActivity",
	"d0"."preferences" AS "preferences",
	"d0"."interests" AS "interests"
FROM
	"users" AS "d0"
WHERE
	(
		(
			(
				(LOWER("d0"."name") LIKE 'john%')
				OR ("d0"."name" LIKE 'jane%')
			)
		)
		AND ("d0"."age" BETWEEN 25 AND 35)
	)
```
</CodeTab>
</CodeTabs>

### Relations Filters

With Drizzle Relations, you can filter not only by the table you're querying but also by any table you include in the query.

**Example:** Get all `users` whose ID>10 and who have at least one post with content starting with "M"
```ts
const usersWithPosts = await db.query.usersTable.findMany({
  where: {
    id: {
      gt: 10
    },
    posts: {
      content: {
        like: 'M%'
      }
    }
  },
});
```

**Example:** Get all `users` with posts, only if user has at least 1 post
```ts
const response = await db.query.users.findMany({
  with: {
    posts: true,
  },
  where: {
    posts: true,
  },
});
```

### Limit & Offset
Drizzle ORM provides `limit` & `offset` API for queries and for the nested entities.
  
**Find 5 posts:**
```typescript copy
await db.query.posts.findMany({
	limit: 5,
});
```

**Find posts and get 3 comments at most:**
```typescript copy
await db.query.posts.findMany({
	with: {
		comments: {
			limit: 3,
		},
	},
});
```

<Callout type="warning" emoji="⚠️">
  `offset` now can be used in with tables as well!
</Callout>
```typescript 
await db.query.posts.findMany({
	limit: 5,
	offset: 2, // correct ✅
	with: {
		comments: {
			offset: 3, // correct ✅
			limit: 3,
		},
	},
});
```

Find posts with comments from the 6th to the 10th post:
```typescript copy
await db.query.posts.findMany({
	with: {
		comments: true,
	},
  limit: 5,
  offset: 5,
});
```

### Order By
Drizzle provides API for ordering in the relational query builder.  

You can use same ordering **[core API](/docs/sqlite/select#order-by)** or use
`order by` operator from the callback with no imports.  

<Callout title='important'>
When you use multiple `orderBy` statements in the same table, they will be included in the query in the same order in which you added them
</Callout>

<Section>
```typescript copy
await db.query.posts.findMany({
  orderBy: {
    id: "asc",
  },
});
```
</Section>

**Order by `asc` + `desc`:**
```typescript copy
  await db.query.posts.findMany({
    orderBy: { id: "asc" },
    with: {
      comments: {
        orderBy: { id: "desc" },
      },
    },
  });
```

You can also use custom `sql` in order by statement:

```typescript copy
await db.query.posts.findMany({
  orderBy: (t) => sql`${t.id} asc`,
  with: {
    comments: {
      orderBy: (t, { desc }) => desc(t.id),
    },
  },
});
```

### Include custom fields
Relational query API lets you add custom additional fields. 
It's useful when you need to retrieve data and apply additional functions to it.
<Callout type="warning" emoji="⚠️">
	As of now aggregations are not supported in `extras`, please use **[`core queries`](/docs/sqlite/select)** for that.
</Callout>

<Section>
```typescript copy {5}
import { sql } from 'drizzle-orm';

await db.query.users.findMany({
  extras: {
    loweredName: (table) => sql`lower(${table.name})`,
  },
});
```
```typescript copy {3}
await db.query.users.findMany({
	extras: {
		loweredName: (users, { sql }) => sql`lower(${users.name})`,
	},
})
```
</Section>

`lowerName` as a key will be included to all fields in returned object.

<Callout type="warning" emoji="⚠️">
  If you will specify `.as("<alias>")` for any extras field - drizzle will ignore it
</Callout>

To retrieve all users with groups, but with the fullName field included (which is a concatenation of firstName and lastName), 
you can use the following query with the Drizzle relational query builder.

<Section>
```typescript copy
const res = await db.query.users.findMany({
	extras: {
		fullName: (users, { sql }) => sql<string>`concat(${users.name}, " ", ${users.name})`,
	},
	with: {
		groups: true,
	},
});
```
```ts
// result type
const res: {
    id: number;
    name: string;
    age: number | null;
    invitedBy: number | null;
    fullName: string;
    groups: {
        id: number;
        name: string;
        description: string | null;
    }[];
}[]
```
</Section>

To retrieve all posts with comments and add an additional field to calculate the size of the post content and the size of each comment content:
<Section>
```typescript copy
const res = await db.query.posts.findMany({
	extras: {
		contentLength: (table, { sql }) => sql<number>`length(${table.content})`,
	},
	with: {
		comments: {
			extras: {
				commentSize: (table, { sql }) => sql<number>`length(${table.content})`,
			},
		},
	},
});
```
```ts
// result type
const res: {
    id: number;
    content: string;
    authorId: number | null;
    createdAt: Date;
    contentLength: number;
    comments: {
        id: number;
        content: string;
        createdAt: Date;
        creator: number | null;
        postId: number | null;
        commentSize: number;
    }[];
}[]
```
</Section>

### Include subqueries

You can also use subqueries within Relational Queries to leverage the power of custom SQL syntax

**Get users with posts and total posts count for each user**
```ts
import { posts } from './schema';
import { eq } from 'drizzle-orm';

await db.query.users.findMany({
  with: {
    posts: true
  },
  extras: {
    totalPostsCount: (table) => db.$count(posts, eq(posts.authorId, table.id)),
  }
});
```
```sql
SELECT
	"d0"."id" AS "id",
	"d0"."name" AS "name",
	"d0"."age" AS "age",
	"d0"."invited_by" AS "invitedBy",
	(
		(
			SELECT
				count(*)
			FROM
				"posts"
			WHERE
				"posts"."author_id" = "d0"."id"
		)
	) AS "totalPostsCount",
	coalesce(
		(
			SELECT
				json_group_array(json_object('id', "id", 'content', "content", 'authorId', "authorId", 'createdAt', "createdAt")) AS "r"
			FROM
				(
					SELECT
						"d1"."id" AS "id",
						"d1"."content" AS "content",
						"d1"."author_id" AS "authorId",
						"d1"."created_at" AS "createdAt"
					FROM
						"posts" AS "d1"
					WHERE
						"d0"."id" = "d1"."author_id"
				) AS "t"
		),
		jsonb_array ()
	) AS "posts"
FROM
	"users" AS "d0"
```

### Prepared statements
Prepared statements are designed to massively improve query performance — [see here.](/docs/sqlite/perf-queries)

In this section, you can learn how to define placeholders and execute prepared statements 
using the Drizzle relational query builder.

##### **Placeholder in `where`**

<Section>
```ts copy
const prepared = db.query.users.findMany({
    where: { id: { eq: sql.placeholder("id") } },
    with: {
      posts: {
        where: { id: 1 },
      },
    },
}).prepare();

const usersWithPosts = await prepared.execute({ id: 1 });
```
</Section>

##### **Placeholder in `limit`**

<Section>
```ts copy
const prepared = db.query.users.findMany({
    with: {
      posts: {
        limit: sql.placeholder("limit"),
      },
    },
  }).prepare();

const usersWithPosts = await prepared.execute({ limit: 1 });
```
</Section>

##### **Placeholder in `offset`**

<Section>
```ts copy
const prepared = db.query.users.findMany({
	offset: sql.placeholder('offset'),
	with: {
		posts: true,
	},
}).prepare();

const usersWithPosts = await prepared.execute({ offset: 1 });
```
</Section>

##### **Multiple placeholders**

<Section>
```ts copy
const prepared = db.query.users.findMany({
    limit: sql.placeholder("uLimit"),
    offset: sql.placeholder("uOffset"),
    where: {
      OR: [{ id: { eq: sql.placeholder("id") } }, { id: 3 }],
    },
    with: {
      posts: {
        where: { id: { eq: sql.placeholder("pid") } },
        limit: sql.placeholder("pLimit"),
      },
    },
}).prepare();

const usersWithPosts = await prepared.execute({ pLimit: 1, uLimit: 3, uOffset: 1, id: 2, pid: 6 });
```
</Section>


Source: https://orm.drizzle.team/docs/sqlite/seed-functions

import Callout from '@mdx/Callout.astro';
import Tab from "@mdx/Tab.astro";
import Tabs from "@mdx/Tabs.astro";

# Generators

<Callout title='warning'>
For now, specifying `arraySize` along with `isUnique` in generators that support it will result in unique values being generated (not unique arrays), which will then be packed into arrays.
</Callout>

## ---

### `default`

<rem025 />
Generates the same given value each time the generator is called.

|  | param          | default     | type
|:-| :--------      | :--------   | :--------
|  |`defaultValue`  |--           |`any`
|  |`arraySize`     |--           |`number`

<rem025 />

```ts 
import { seed } from "drizzle-seed";

await seed(db, schema, { count: 1000 }).refine((funcs) => ({
  posts: {
    columns: {
      content: funcs.default({
        // value you want to generate
        defaultValue: "post content",

        // number of elements in each one-dimensional array. 
        // (If specified, arrays will be generated.)
        arraySize: 3
      }),
    },
  },
}));

```

### `valuesFromArray`

<rem025 />
Generates values from given array

|  | param      | default                     | type
|:-| :--------  | :--------                   | :--------
|  |`values`    |--                           |`any[]` \| `{ weight: number; values: any[] }[]`
|  |`isUnique`  |`database column uniqueness` |`boolean`
|  |`arraySize` |--                           |`number`


<rem025 />
```ts 
import { seed } from "drizzle-seed";

await seed(db, schema, { count: 1000 }).refine((funcs) => ({
  posts: {
    columns: {
      title: funcs.valuesFromArray({
        // Array of values you want to generate (can be an array of weighted values)
        values: ["Title1", "Title2", "Title3", "Title4", "Title5"],

        // Property that controls whether the generated values will be unique or not
        isUnique: true,
        
        // number of elements in each one-dimensional array. 
        // (If specified, arrays will be generated.)
        arraySize: 3
      }),
    },
  },
}));

```

### `intPrimaryKey`

<rem025 />
Generates sequential integers starting from 1.

|  | param      | default    | type
|:-| :--------  | :--------  | :--------
|  |--          |--          |--

<rem025 />

```ts 
import { seed } from "drizzle-seed";

await seed(db, schema, { count: 1000 }).refine((funcs) => ({
  posts: {
    columns: {
      id: funcs.intPrimaryKey(),
    },
  },
}));

```

### `number`

<rem025 />
Generates numbers with a floating point within the given range

|  | param      | default                                                                                               | type
|:-| :--------  | :--------                                                                                             | :--------
|  |`isUnique`  |`database column uniqueness`                                                                           |`boolean`
|  |`precision` |`100`                                                                                                  |`number`
|  |`maxValue`  |``` `precision * 1000` if isUnique equals false``` ``` `precision * count` if isUnique equals true```  |`number`
|  |`minValue`  |`-maxValue`                                                                                            |`number`
|  |`arraySize` |--                                                                                                     |`number`

<rem025 />
```ts 
import { seed } from "drizzle-seed";

await seed(db, schema, { count: 1000 }).refine((funcs) => ({
  products: {
    columns: {
      unitPrice: funcs.number({
        // lower border of range.
        minValue: 10,

        // upper border of range.
        maxValue: 120,
        
        // precision of generated number:
        // precision equals 10 means that values will be accurate to one tenth (1.2, 34.6);
        // precision equals 100 means that values will be accurate to one hundredth (1.23, 34.67).
        precision: 100,

        // property that controls if generated values gonna be unique or not.
        isUnique: false,

        // number of elements in each one-dimensional array. 
        // (If specified, arrays will be generated.)
        arraySize: 3
      }),
    },
  },
}));

```

### `int`

<rem025 />
Generates integers within the given range

|  | param      | default                                                                            | type
|:-| :--------  | :--------                                                                          | :--------
|  |`isUnique`  |`database column uniqueness`                                                        |`boolean`
|  |`maxValue`  |``` `1000` if isUnique equals false``` ``` `count * 10` if isUnique equals true```  |`number \| bigint`
|  |`minValue`  |`-maxValue`                                                                         |`number \| bigint`
|  |`arraySize` |--                                                                                  |`number`

<rem025 />
```ts 
import { seed } from "drizzle-seed";

await seed(db, schema, { count: 1000 }).refine((funcs) => ({
  products: {
    columns: {
      unitsInStock: funcs.int({
        // lower border of range.
        minValue: 0,

        // lower border of range.
        maxValue: 100,

        // property that controls if generated values gonna be unique or not.
        isUnique: false,

        // number of elements in each one-dimensional array. 
        // (If specified, arrays will be generated.)
        arraySize: 3
      }),
    },
  },
}));

```

### `boolean`

<rem025 />
Generates boolean values (true or false)

|  | param      | default    | type
|:-| :--------  | :--------  | :--------
|  |`arraySize` |--          |`number`

<rem025 />
```ts 
import { seed } from "drizzle-seed";

await seed(db, schema, { count: 1000 }).refine((funcs) => ({
  users: {
    columns: {
      isAvailable: funcs.boolean({
        // number of elements in each one-dimensional array. 
        // (If specified, arrays will be generated.)
        arraySize: 3
      }),
    },
  },
}));

```

### `date`

<rem025 />
Generates a date within the given range

|  | param      | default                                                                                                   | type
|:-| :--------  | :--------------                                                                                           | :--------
|  |`minDate`   |``` `'2024-05-08' - 4 years` - if maxDate is not set``` ``` `maxDate - 8 years`  - if maxDate is set ```   |`string \| Date`
|  |`maxDate`   |``` `'2024-05-08' + 4 years` - if minDate is not set``` ``` `minDate + 8 years`  - if minDate is set ```   |`string \| Date`
|  |`arraySize` |--                                                                                                         |`number`

<Callout type='warning'>
If only one of the parameters (`minDate` or `maxDate`) is provided, the unspecified parameter will be calculated by adding or subtracting 8 years to/from the specified one
</Callout>

<rem025 />
```ts 
import { seed } from "drizzle-seed";

await seed(db, schema, { count: 1000 }).refine((funcs) => ({
  users: {
    columns: {
      birthDate: funcs.date({
        // lower border of range.
        minDate: "1990-01-01",

        // upper border of range.
        maxDate: "2010-12-31",

        // number of elements in each one-dimensional array. 
        // (If specified, arrays will be generated.)
        arraySize: 3
      }),
    },
  },
}));

```

### `time`

<rem025 />
Generates time in 24-hour format

|  | param      | default             | type
|:-| :--------  | :--------           | :--------
|  |`min`       |`'00:00:00.000Z'`    |`string \| Date`
|  |`max`       |`'23:59:59.999Z'`    |`string \| Date`
|  |`arraySize` |--                   |`number`

<rem025 />
```ts 
import { seed } from "drizzle-seed";

await seed(db, schema, { count: 1000 }).refine((funcs) => ({
  users: {
    columns: {
      birthTime: funcs.time({
        // lower border of range.
        min: "11:12:13.141",

        // upper border of range.
        max: "15:16:17.181",

        // number of elements in each one-dimensional array. 
        // (If specified, arrays will be generated.)
        arraySize: 3
      }),
    },
  },
}));

```

### `timestamp`

<rem025 />
Generates timestamps

|  | param           | default                                                                                       | type
|:-| :--------       | :--------                                                                                     | :--------
|  |`min`            |``` `'2024-05-08' - 2 years` - if max is not set``` ``` `max - 4 years`  - if max is set ```   |`string \| Date`
|  |`max`            |``` `'2024-05-08' + 2 years` - if min is not set``` ``` `min + 4 years`  - if min is set ```   |`string \| Date`
|  |`arraySize`      |--                                                                                             |`number`

<rem025 />
```ts 
import { seed } from "drizzle-seed";

await seed(db, schema, { count: 1000 }).refine((funcs) => ({
  orders: {
    columns: {
      shippedDate: funcs.timestamp({
        // lower border of range.
        min: "2025-03-07T11:12:13.141",

        // upper border of range.
        max: "2025-03-08T15:16:17.181",

        // number of elements in each one-dimensional array. 
        // (If specified, arrays will be generated.)
        arraySize: 3
      }),
    },
  },
}));

```

### `datetime`

<rem025 />
Generates datetime objects

|  | param        | default                                                                                       | type
|:-| :--------    | :--------                                                                                     | :--------
|  |`min`         |``` `'2024-05-08' - 2 years` - if max is not set``` ``` `max - 4 years`  - if max is set ```   |`string \| Date`
|  |`max`         |``` `'2024-05-08' + 2 years` - if min is not set``` ``` `min + 4 years`  - if min is set ```   |`string \| Date`
|  |`arraySize`   |--                                                                                             |`number`
<rem025 />
```ts 
import { seed } from "drizzle-seed";

await seed(db, schema, { count: 1000 }).refine((funcs) => ({
  orders: {
    columns: {
      shippedDate: funcs.datetime({
        // lower border of range.
        min: "2025-03-07 13:12:13Z",
        
        // upper border of range.
        max: "2025-03-09 15:12:13Z",

        // number of elements in each one-dimensional array. 
        // (If specified, arrays will be generated.)
        arraySize: 3
      }),
    },
  },
}));

```

### `year`

<rem025 />
Generates years in `YYYY` format

|  | param      | default    | type
|:-| :--------  | :--------  | :--------
|  |`arraySize` |--          |`number`

<rem025 />
```ts 
import { seed } from "drizzle-seed";

await seed(db, schema, { count: 1000 }).refine((funcs) => ({
  users: {
    columns: {
      birthYear: funcs.year({
        // number of elements in each one-dimensional array. 
        // (If specified, arrays will be generated.)
        arraySize: 3
      }),
    },
  },
}));

```

### `json`

<rem025 />
Generates JSON objects with a fixed structure

```ts
{ email, name, isGraduated, hasJob, salary, startedWorking, visitedCountries}

// or

{ email, name, isGraduated, hasJob, visitedCountries }
```

> The JSON structure will be picked randomly

|  | param      | default    | type
|:-| :--------  | :--------  | :--------
|  |`arraySize` |--          |`number`

<rem025 />
```ts 
import { seed } from "drizzle-seed";

await seed(db, schema, { count: 1000 }).refine((funcs) => ({
  users: {
    columns: {
      metadata: funcs.json({
        // number of elements in each one-dimensional array. 
        // (If specified, arrays will be generated.)
        arraySize: 3
      }),
    },
  },
}));

```

### `interval`

<rem025 />
Generates time intervals.

Example of a generated value: `1 year 12 days 5 minutes`

|  | param      | default                     | type
|:-| :--------  | :--------                   | :--------
|  |`isUnique`  |`database column uniqueness` |`boolean`
|  |`arraySize` |--                           |`number`

<rem025 />
```ts 
import { seed } from "drizzle-seed";

await seed(db, schema, { count: 1000 }).refine((funcs) => ({
  users: {
    columns: {
      timeSpentOnWebsite: funcs.interval({
        // `isUnique` - property that controls whether the generated values will be unique or not
        isUnique: true,

        // number of elements in each one-dimensional array. 
        // (If specified, arrays will be generated.)
        arraySize: 3
      }),
    },
  },
}));

```

### `string`

<rem025 />
Generates random strings

|  | param      | default                     | type
|:-| :--------  | :--------                   | :--------
|  |`isUnique`  |`database column uniqueness` |`boolean`
|  |`arraySize` |--                           |`number`

<rem025 />
```ts 
import { seed } from "drizzle-seed";

await seed(db, schema, { count: 1000 }).refine((funcs) => ({
  users: {
    columns: {
      hashedPassword: funcs.string({
        // `isUnique` - property that controls whether the generated values will be unique or not
        isUnique: false,
        
        // number of elements in each one-dimensional array. 
        // (If specified, arrays will be generated.)
        arraySize: 3
      }),
    },
  },
}));

```

### `uuid`

<rem025 />
Generates v4 UUID strings

|  | param      | default    | type
|:-| :--------  | :--------  | :--------
|  |`arraySize` |--          |`number`

<rem025 />
```ts 
import { seed } from "drizzle-seed";
await seed(db, schema, { count: 1000 }).refine((funcs) => ({
  products: {
    columns: {
      id: funcs.uuid({
        // number of elements in each one-dimensional array. 
        // (If specified, arrays will be generated.)
        arraySize: 3
      }),
    },
  },
}));
```

### `firstName`

<rem025 />
Generates a person's first name

|  | param      | default                     | type
|:-| :--------  | :--------                   | :--------
|  |`isUnique`  |`database column uniqueness` |`boolean`
|  |`arraySize` |--                           |`number`

<rem025 />
```ts 
import { seed } from "drizzle-seed";

await seed(db, schema, { count: 1000 }).refine((funcs) => ({
  users: {
    columns: {
      firstName: funcs.firstName({
        // `isUnique` - property that controls whether the generated values will be unique or not
        isUnique: true,

        // number of elements in each one-dimensional array. 
        // (If specified, arrays will be generated.)
        arraySize: 3
      }),
    },
  },
}));

```

### `lastName`

<rem025 />
Generates a person's last name

|  | param      | default                     | type
|:-| :--------  | :--------                   | :--------
|  |`isUnique`  |`database column uniqueness` |`boolean`
|  |`arraySize` |--                           |`number`

<rem025 />
```ts 
import { seed } from "drizzle-seed";

await seed(db, schema, { count: 1000 }).refine((funcs) => ({
  users: {
    columns: {
      lastName: funcs.lastName({
        // `isUnique` - property that controls whether the generated values will be unique or not
        isUnique: false,
        
        // number of elements in each one-dimensional array. 
        // (If specified, arrays will be generated.)
        arraySize: 3
      }),
    },
  },
}));

```

### `fullName`

<rem025 />
Generates a person's full name

|  | param      | default                     | type
|:-| :--------  | :--------                   | :--------
|  |`isUnique`  |`database column uniqueness` |`boolean`
|  |`arraySize` |--                           |`number`

<rem025 />
```ts 
import { seed } from "drizzle-seed";

await seed(db, schema, { count: 1000 }).refine((funcs) => ({
  users: {
    columns: {
      fullName: funcs.fullName({
        // `isUnique` - property that controls whether the generated values will be unique or not
        isUnique: true,

        // number of elements in each one-dimensional array. 
        // (If specified, arrays will be generated.)
        arraySize: 3
      }),
    },
  },
}));

```

### `email`

<rem025 />
Generates unique email addresses

|  | param      | default    | type
|:-| :--------  | :--------  | :--------
|  |`arraySize` |--          |`number`

<rem025 />
```ts 
import { seed } from "drizzle-seed";

await seed(db, schema, { count: 1000 }).refine((funcs) => ({
  users: {
    columns: {
      email: funcs.email({
        // number of elements in each one-dimensional array. 
        // (If specified, arrays will be generated.)
        arraySize: 3
      }),
    },
  },
}));

```

### `phoneNumber`

<rem025 />
Generates unique phone numbers

|  | param                    | default                                         | type
|:-| :--------                | :--------                                       | :--------
|  |`template`                |--                                               |`string`
|  |`prefixes`                |[Used dataset for prefixes](https://github.com/OleksiiKH0240/drizzle-orm/blob/main/drizzle-seed/src/datasets/phonesInfo.ts)   |`string[]`
|  |`generatedDigitsNumbers`  | `7` - `if prefixes was defined`                 |`number \| number[]`
|  |`arraySize`               |--                                               |`number`

<rem025 />
```ts 
import { seed } from "drizzle-seed";

//generate phone number using template property
await seed(db, schema, { count: 1000 }).refine((funcs) => ({
  users: {
    columns: {
      phoneNumber: funcs.phoneNumber({ 
        // `template` - phone number template, where all '#' symbols will be substituted with generated digits.
        template: "+(380) ###-####",

        // number of elements in each one-dimensional array. 
        // (If specified, arrays will be generated.)
        arraySize: 3
      }),
    },
  },
}));

```
```ts 
import { seed } from "drizzle-seed";

//generate phone number using prefixes and generatedDigitsNumbers properties
await seed(db, schema, { count: 1000 }).refine((funcs) => ({
  users: {
    columns: {
      phoneNumber: funcs.phoneNumber({
        // `prefixes` - array of any string you want to be your phone number prefixes.(not compatible with `template` property)
        prefixes: ["+380 99", "+380 67"],

        // `generatedDigitsNumbers` - number of digits that will be added at the end of prefixes.(not compatible with `template` property)
        generatedDigitsNumbers: 7,

        // number of elements in each one-dimensional array. 
        // (If specified, arrays will be generated.)
        arraySize: 3
      }),
    },
  },
}));

```
```ts 
import { seed } from "drizzle-seed";

// generate phone number using prefixes and generatedDigitsNumbers properties but with different generatedDigitsNumbers for prefixes
await seed(db, schema, { count: 1000 }).refine((funcs) => ({
  users: {
    columns: {
      phoneNumber: funcs.phoneNumber({
        // `prefixes` - array of any string you want to be your phone number prefixes.(not compatible with `template` property)
        prefixes: ["+380 99", "+380 67", "+1"],

        // `generatedDigitsNumbers` - number of digits that will be added at the end of prefixes.(not compatible with `template` property)
        generatedDigitsNumbers: [7, 7, 10],

        // number of elements in each one-dimensional array. 
        // (If specified, arrays will be generated.)
        arraySize: 3
      }),
    },
  },
}));

```
### `country`

<rem025 />
Generates country's names

|  | param      | default                     | type
|:-| :--------  | :--------                   | :--------
|  |`isUnique`  |`database column uniqueness` |`boolean`
|  |`arraySize` |--                           |`number`

<rem025 />

```ts 
import { seed } from "drizzle-seed";

await seed(db, schema, { count: 1000 }).refine((funcs) => ({
  users: {
    columns: {
      country: funcs.country({
        // `isUnique` - property that controls whether the generated values will be unique or not
        isUnique: false,
        
        // number of elements in each one-dimensional array. 
        // (If specified, arrays will be generated.)
        arraySize: 3
      }),
    },
  },
}));

```

### `city`

<rem025 />
Generates city's names

|  | param      | default                     | type
|:-| :--------  | :--------                   | :--------
|  |`isUnique`  |`database column uniqueness` |`boolean`
|  |`arraySize` |--                           |`number`

<rem025 />

```ts 
import { seed } from "drizzle-seed";

await seed(db, schema, { count: 1000 }).refine((funcs) => ({
  users: {
    columns: {
      city: funcs.city({
        // `isUnique` - property that controls whether the generated values will be unique or not
        isUnique: false,

        // number of elements in each one-dimensional array. 
        // (If specified, arrays will be generated.)
        arraySize: 3
      }),
    },
  },
}));

```

### `streetAddress`

<rem025 />
Generates street address

|  | param      | default                     | type
|:-| :--------  | :--------                   | :--------
|  |`isUnique`  |`database column uniqueness` |`boolean`
|  |`arraySize` |--                           |`number`

<rem025 />

```ts 
import { seed } from "drizzle-seed";

await seed(db, schema, { count: 1000 }).refine((funcs) => ({
  users: {
    columns: {
      streetAddress: funcs.streetAddress({
        // `isUnique` - property that controls whether the generated values will be unique or not
        isUnique: false,
        
        // number of elements in each one-dimensional array. 
        // (If specified, arrays will be generated.)
        arraySize: 3 
      }),
    },
  },
}));

```

### `jobTitle`

<rem025 />
Generates job titles

|  | param      | default    | type
|:-| :--------  | :--------  | :--------
|  |`arraySize` |--          |`number`

<rem025 />

```ts 
import { seed } from "drizzle-seed";

await seed(db, schema, { count: 1000 }).refine((funcs) => ({
  users: {
    columns: {
      jobTitle: funcs.jobTitle({
        // number of elements in each one-dimensional array. 
        // (If specified, arrays will be generated.)
        arraySize: 3
      }),
    },
  },
}));

```

### `postcode`

<rem025 />
Generates postal codes

|  | param      | default                     | type
|:-| :--------  | :--------                   | :--------
|  |`isUnique`  |`database column uniqueness` |`boolean`
|  |`arraySize` |--                           |`number`

<rem025 />

```ts 
import { seed } from "drizzle-seed";

await seed(db, schema, { count: 1000 }).refine((funcs) => ({
  users: {
    columns: {
      postcode: funcs.postcode({
        // `isUnique` - property that controls whether the generated values will be unique or not
        isUnique: true,

        // number of elements in each one-dimensional array. 
        // (If specified, arrays will be generated.)
        arraySize: 3
      }),
    },
  },
}));

```

### `state`

<rem025 />
Generates US states

|  | param      | default    | type
|:-| :--------  | :--------  | :--------
|  |`arraySize` |--          |`number`

<rem025 />

```ts 
import { seed } from "drizzle-seed";

await seed(db, schema, { count: 1000 }).refine((funcs) => ({
  users: {
    columns: {
      state: funcs.state({
        // number of elements in each one-dimensional array. 
        // (If specified, arrays will be generated.)
        arraySize: 3
      }),
    },
  },
}));

```

### `companyName`

<rem025 />
Generates random company's names

|  | param      | default                     | type
|:-| :--------  | :--------                   | :--------
|  |`isUnique`  |`database column uniqueness` |`boolean`
|  |`arraySize` |--                           |`number`

<rem025 />

```ts 
import { seed } from "drizzle-seed";

await seed(db, schema, { count: 1000 }).refine((funcs) => ({
  users: {
    columns: {
      company: funcs.companyName({ 
        // `isUnique` - property that controls whether the generated values will be unique or not
        isUnique: true,

        // number of elements in each one-dimensional array. 
        // (If specified, arrays will be generated.)
        arraySize: 3
      }),
    },
  },
}));

```
### `loremIpsum`

<rem025 />
Generates `lorem ipsum` text sentences.

|  | param            | default    | type
|:-| :--------        | :--------  | :--------
|  |`sentencesCount`  | 1          |`number`
|  |`arraySize`       |--          |`number`

<rem025 />

```ts 
import { seed } from "drizzle-seed";

await seed(db, schema, { count: 1000 }).refine((funcs) => ({
  posts: {
    columns: {
      content: funcs.loremIpsum({
        // `sentencesCount` - number of sentences you want to generate as one generated value(string).
        sentencesCount: 2,

        // number of elements in each one-dimensional array. 
        // (If specified, arrays will be generated.)
        arraySize: 3
      }),
    },
  },
}));

```

### `point`

<rem025 />
Generates 2D points within specified ranges for x and y coordinates.

|  | param       | default                                                                                 | type
|:-| :--------   | :--------                                                                               | :--------
|  |`isUnique`   |`database column uniqueness`                                                             |`boolean`
|  |`maxXValue`  |``` `10 * 1000` if isUnique equals false``` ``` `10 * count` if isUnique equals true```  |`number`
|  |`minXValue`  |`-maxXValue`                                                                             |`number`
|  |`maxYValue`  |``` `10 * 1000` if isUnique equals false``` ``` `10 * count` if isUnique equals true```  |`number`
|  |`minYValue`  |`-maxYValue`                                                                             |`number`
|  |`arraySize`  |--                                                                                       |`number`


<rem025 />

```ts 
import { seed } from "drizzle-seed";

await seed(db, schema, { count: 1000 }).refine((funcs) => ({
  triangles: {
    columns: {
      pointCoords: funcs.point({
        // `isUnique` - property that controls if generated values gonna be unique or not.
        isUnique: true,

        // `minXValue` - lower bound of range for x coordinate.
        minXValue: -5,

        // `maxXValue` - upper bound of range for x coordinate.
        maxXValue: 20,

        // `minYValue` - lower bound of range for y coordinate.
        minYValue: 0,

        // `maxYValue` - upper bound of range for y coordinate.
        maxYValue: 30,

        // number of elements in each one-dimensional array. 
        // (If specified, arrays will be generated.)
        arraySize: 3
      }),
    },
  },
}));

```

### `line`

<rem025 />
Generates 2D lines within specified ranges for a, b and c parameters of line.

```
line equation: a*x + b*y + c = 0
```

|  | param       | default                                                                                 | type
|:-| :--------   | :--------                                                                               | :--------
|  |`isUnique`   |`database column uniqueness`                                                             |`boolean`
|  |`maxAValue`  |``` `10 * 1000` if isUnique equals false``` ``` `10 * count` if isUnique equals true```  |`number`
|  |`minAValue`  |`-maxAValue`                                                                             |`number`
|  |`maxBValue`  |``` `10 * 1000` if isUnique equals false``` ``` `10 * count` if isUnique equals true```  |`number`
|  |`minBValue`  |`-maxBValue`                                                                             |`number`
|  |`maxCValue`  |``` `10 * 1000` if isUnique equals false``` ``` `10 * count` if isUnique equals true```  |`number`
|  |`minCValue`  |`-maxCValue`                                                                             |`number`
|  |`arraySize`  |--                                                                                       |`number`
<rem025 />

```ts 
import { seed } from "drizzle-seed";

await seed(db, schema, { count: 1000 }).refine((funcs) => ({
  lines: {
    columns: {
      lineParams: funcs.point({
        // `isUnique` - property that controls if generated values gonna be unique or not.
        isUnique: true,

        // `minAValue` - lower bound of range for a parameter.
        minAValue: -5,

        // `maxAValue` - upper bound of range for x parameter.
        maxAValue: 20,

        // `minBValue` - lower bound of range for y parameter.
        minBValue: 0,

        // `maxBValue` - upper bound of range for y parameter.
        maxBValue: 30,

        // `minCValue` - lower bound of range for y parameter.
        minCValue: 0,

        // `maxCValue` - upper bound of range for y parameter.
        maxCValue: 10,

        // number of elements in each one-dimensional array. 
        // (If specified, arrays will be generated.)
        arraySize: 3
      }),
    },
  },
}));

```

### `bitString`

<rem025 />
Generates bit strings based on specified parameters.

|  | param       | default                                                                                 | type
|:-| :--------   | :--------                                                                               | :--------
|  |`isUnique`   |`database column uniqueness`                                                             |`boolean`
|  |`dimensions` |`database column bit-length`                                                             |`number`
|  |`arraySize`  |--                                                                                       |`number`
<rem025 />

```ts 
import { seed } from "drizzle-seed";

await seed(db, schema, { count: 1000 }).refine((funcs) => ({
  bitStringTable: {
    columns: {
      bit: funcs.bitString({
        // desired length of each bit string (e.g., `dimensions = 3` produces values like `'010'`).
        dimensions: 12,

        // property that controls if generated values gonna be unique or not;
        isUnique: true,

        // number of elements in each one-dimensional array (If specified, arrays will be generated);
        arraySize: 3,
      }),
    },
  },
}));

```

### `inet`

<rem025 />
Generates ip addresses based on specified parameters.

|  | param       | default                                                                                 | type
|:-| :--------   | :--------                                                                               | :--------
|  |`isUnique`   |`database column uniqueness`                                                             |`boolean`
|  |`arraySize`  |--                                                                                       |`number`
|  |`ipAddress`  |`'ipv4'`                                                                                 |`'ipv4' \| 'ipv6'`
|  |`includeCidr`|`true`                                                                                   |`boolean`
<rem025 />

```ts 
import { seed } from "drizzle-seed";

await seed(db, schema, { count: 1000 }).refine((funcs) => ({
  inetTable: {
    columns: {
      inet: funcs.inet({
        // property that controls if generated values gonna be unique or not;
        isUnique: true,

        // number of elements in each one-dimensional array (If specified, arrays will be generated);
        arraySize: 3,

        // type of IP address to generate — either "ipv4" or "ipv6";
        ipAddress: "ipv4",

        // determines whether generated IPs include a CIDR suffix.
        includeCidr: true,
      }),
    },
  },
}));
```


### `vector`

<rem025 />
Generates vectors based on the provided parameters.

|  | param          | default                                                      | type
|:-| :--------      | :--------                                                    | :--------
|  |`isUnique`      |`database column uniqueness`                                  |`boolean`
|  |`arraySize`     |--                                                            |`number`
|  |`decimalPlaces` |`2`                                                           |`number`
|  |`dimensions`    |`database column’s dimensions`                                |`number`
|  |`minValue`      |`-1000`                                                       |`number`
|  |`maxValue`      |`1000`                                                        |`number`
<rem025 />

```ts 
import { seed } from "drizzle-seed";

await seed(db, schema, { count: 1000 }).refine((funcs) => ({
  vectorTable: {
    columns: {
      vector: funcs.vector({
        // property that controls if generated values gonna be unique or not;
        isUnique: true,

        // number of elements in each one-dimensional array (If specified, arrays will be generated);
        arraySize: 3,

        // number of decimal places for each vector element (e.g., `decimalPlaces = 3` produces values like `1.123`);
        decimalPlaces: 5,

        // number of elements in each generated vector (e.g., `dimensions = 3` produces values like `[1,2,3]`);
        dimensions: 12,

        // minimum allowed value for each vector element;
        minValue: -100,

        // maximum allowed value for each vector element.
        maxValue: 100,
      }),
    },
  },
}));

```

Source: https://orm.drizzle.team/docs/sqlite/seed-overview

import Npm from "@mdx/Npm.astro";
import Tab from "@mdx/Tab.astro";
import Tabs from "@mdx/Tabs.astro";
import Callout from '@mdx/Callout.astro';
import CodeTabs from "@mdx/CodeTabs.astro";
import Section from "@mdx/Section.astro";

# Drizzle Seed

`drizzle-seed` is a TypeScript library that helps you generate deterministic, yet realistic,
fake data to populate your database. By leveraging a seedable pseudorandom number generator (pRNG),
it ensures that the data you generate is consistent and reproducible across different runs.
This is especially useful for testing, development, and debugging purposes.

#### What is Deterministic Data Generation?

Deterministic data generation means that the same input will always produce the same output.
In the context of `drizzle-seed`, when you initialize the library with the same seed number,
it will generate the same sequence of fake data every time. This allows for predictable and repeatable data sets.

#### Pseudorandom Number Generator (pRNG)

A pseudorandom number generator is an algorithm that produces a sequence of numbers
that approximates the properties of random numbers. However, because it's based on an initial value
called a seed, you can control its randomness. By using the same seed, the pRNG will produce the
same sequence of numbers, making your data generation process reproducible.

#### Benefits of Using a pRNG:

- Consistency: Ensures that your tests run on the same data every time.
- Debugging: Makes it easier to reproduce and fix bugs by providing a consistent data set.
- Collaboration: Team members can share seed numbers to work with the same data sets.

With drizzle-seed, you get the best of both worlds: the ability to generate realistic fake data and the control to reproduce it whenever needed.

## Installation

<Npm>drizzle-seed</Npm>

## Basic Usage

In this example we will create 10 users with random names and ids

```ts {12}
import { sqliteTable, integer, text } from "drizzle-orm/sqlite-core";
import { drizzle } from "drizzle-orm/better-sqlite3";
import { seed } from "drizzle-seed";

const users = sqliteTable("users", {
  id: integer().primaryKey({ autoIncrement: true }),
  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

```ts
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

```ts
await seed(db, schema, { seed: 12345 });
```

## Reset database

With `drizzle-seed`, you can easily reset your database and seed it with new values, for example, in your test suites

```ts
// path to a file with schema you want to reset
import * as schema from "./schema.ts";
import { reset } from "drizzle-seed";

async function main() {
  const db = drizzle(process.env.DATABASE_URL!);
  await reset(db, schema);
}

main();
```

Different dialects will have different strategies for database resetting. For SQLite:

For SQLite, the `drizzle-seed` package will first disable the `foreign_keys` pragma to ensure the next step won't fail, and then generate `DELETE FROM` statements to empty the content of all tables

```sql
PRAGMA foreign_keys = OFF;
DELETE FROM tableName1;
DELETE FROM tableName2;
...
PRAGMA foreign_keys = ON;
```

## Refinements

In case you need to change the behavior of the seed generator functions that `drizzle-seed` uses by default, you can specify your own implementation and even use your own list of values for the seeding process

`.refine` is a callback that receives a list of all available generator functions from `drizzle-seed`. It should return an object with keys representing the tables you want to refine, defining their behavior as needed. 
Each table can specify several properties to simplify seeding your database:

<rem025 />

- `columns`: Refine the default behavior of each column by specifying the required generator function, or exclude the column from seeding by specifying `false`.
- `count`: Specify the number of rows to insert into the database. By default, it's 10. If a global count is defined in the `seed()` options, the count defined here will override it for this specific table.
- `with`: Define how many referenced entities to create for each parent table if you want to generate associated entities.

<Callout title='info'>
You can also specify a weighted random distribution for the number of referenced values you want to create. For details on this API, you can refer to [Weighted Random docs](#weighted-random) docs section
</Callout>

**API**
```ts
await seed(db, schema).refine((f) => ({
  users: {
    columns: {},
    count: 10,
    with: {
        posts: 10
    }
  },
}));
```

Let's check a few examples with an explanation of what will happen:

```ts filename='schema.ts'
import { sqliteTable, integer, text } from "drizzle-orm/sqlite-core";

export const users = sqliteTable("users", {
  id: integer().primaryKey({ autoIncrement: true }),
  name: text().notNull(),
});

export const posts = sqliteTable("posts", {
  id: integer().primaryKey({ autoIncrement: true }),
  description: text(),
  userId: integer().references(() => users.id),
});
```

**Example 1**: Seed only the `users` table with 20 entities and with refined seed logic for the `name` column
```ts filename='index.ts'
import { drizzle } from "drizzle-orm/better-sqlite3";
import { seed } from "drizzle-seed";
import * as schema from './schema.ts'

async function main() {
  const db = drizzle(process.env.DATABASE_URL!);

  await seed(db, { users: schema.users }).refine((f) => ({
    users: {
        columns: {
            name: f.fullName(),
        },
        count: 20
    }
  }));
}

main();
```

**Example 2**: Seed only the `users` table, excluding the `name` column from seeding
```ts filename='index.ts'
import { drizzle } from "drizzle-orm/better-sqlite3";
import { seed } from "drizzle-seed";
import * as schema from './schema.ts'

async function main() {
  const db = drizzle(process.env.DATABASE_URL!);

  await seed(db, { users: schema.users }).refine((f) => ({
    users: {
        columns: {
            name: false, // the name column will not be seeded, allowing the database to use its default value.
        }
    }
  }));
}

main();
```

**Example 3**: Seed the `users` table with 20 entities and add 10 `posts` for each `user` by seeding the `posts` table and creating a reference from `posts` to `users`
```ts filename='index.ts'
import { drizzle } from "drizzle-orm/better-sqlite3";
import { seed } from "drizzle-seed";
import * as schema from './schema.ts'

async function main() {
  const db = drizzle(process.env.DATABASE_URL!);

  await seed(db, schema).refine((f) => ({
    users: {
        count: 20,
        with: {
            posts: 10
        }
    }
  }));
}

main();
```

**Example 4**: Seed the `users` table with 5 entities and populate the database with 100 `posts` without connecting them to the `users` entities. Refine `id` generation for `users` so 
that it will give any int from `10000` to `20000` and remains unique, and refine `posts` to retrieve values from a self-defined array
```ts filename='index.ts'
import { drizzle } from "drizzle-orm/better-sqlite3";
import { seed } from "drizzle-seed";
import * as schema from './schema.ts'

async function main() {
  const db = drizzle(process.env.DATABASE_URL!);

  await seed(db, schema).refine((f) => ({
    users: {
        count: 5,
        columns: {
            id: f.int({
              minValue: 10000,
              maxValue: 20000,
              isUnique: true,
            }),
        }
    },
    posts: {
        count: 100,
        columns: {
            description: f.valuesFromArray({
            values: [
                "The sun set behind the mountains, painting the sky in hues of orange and purple", 
                "I can't believe how good this homemade pizza turned out!", 
                "Sometimes, all you need is a good book and a quiet corner.", 
                "Who else thinks rainy days are perfect for binge-watching old movies?", 
                "Tried a new hiking trail today and found the most amazing waterfall!",
                // ...
            ],
          })
        }
    }
  }));
}

main();
```

<Callout type='warning'>
There are many more possibilities that we will define in these docs, but for now, you can explore a few sections in this documentation. Check the [Generators](/docs/sqlite/seed-functions) section to get familiar with all the available generator functions you can use.

A particularly great feature is the ability to use weighted randomization, both for generator values created for a column and for determining the number of related entities that can be generated by `drizzle-seed`.

Please check [Weighted Random docs](#weighted-random) for more info.
</Callout>


## Weighted Random

There may be cases where you need to use multiple datasets with a different priority that should be inserted into your database during the seed stage. For such cases, drizzle-seed provides an API called weighted random

The Drizzle Seed package has a few places where weighted random can be used:

- Columns inside each table refinements
- The `with` property, determining the amount of related entities to be created

Let's check an example for both:

```ts filename="schema.ts"
import { sqliteTable, integer, text, text, real } from "drizzle-orm/sqlite-core";

export const orders = sqliteTable(
  "orders",
  {
    id: integer().primaryKey({ autoIncrement: true }),
    name: text().notNull(),
    quantityPerUnit: text().notNull(),
    unitPrice: real().notNull(),
    unitsInStock: integer().notNull(),
    unitsOnOrder: integer().notNull(),
    reorderLevel: integer().notNull(),
    discontinued: integer().notNull(),
  }
);

export const details = sqliteTable(
  "details",
  {
    unitPrice: real().notNull(),
    quantity: integer().notNull(),
    discount: real().notNull(),

    orderId: integer()
      .notNull()
      .references(() => orders.id, { onDelete: "cascade" }),
  }
);
```

**Example 1**: Refine the `unitPrice` generation logic to generate `5000` random prices, with a 30% chance of prices between 10-100 and a 70% chance of prices between 100-300

```ts filename="index.ts"
import { drizzle } from "drizzle-orm/better-sqlite3";
import { seed } from "drizzle-seed";
import * as schema from './schema.ts'

async function main() {
  const db = drizzle(process.env.DATABASE_URL!);

  await seed(db, schema).refine((f) => ({
    orders: {
       count: 5000,
       columns: {
           unitPrice: f.weightedRandom(
               [
                   {
                       weight: 0.3,
                       value: funcs.int({ minValue: 10, maxValue: 100 })
                   },
                   {
                       weight: 0.7,
                       value: funcs.number({ minValue: 100, maxValue: 300, precision: 100 })
                   }
               ]
           ),
       }
    }
  }));
}

main();
```

**Example 2**: For each order, generate 1 to 3 details with a 60% chance, 5 to 7 details with a 30% chance, and 8 to 10 details with a 10% chance

```ts filename="index.ts"
import { drizzle } from "drizzle-orm/better-sqlite3";
import { seed } from "drizzle-seed";
import * as schema from './schema.ts'

async function main() {
  const db = drizzle(process.env.DATABASE_URL!);

  await seed(db, schema).refine((f) => ({
    orders: {
       with: {
           details:
               [
                   { weight: 0.6, count: [1, 2, 3] },
                   { weight: 0.3, count: [5, 6, 7] },
                   { weight: 0.1, count: [8, 9, 10] },
               ]
       }
    }
  }));
}

main();
```

## Complex example

<CodeTabs items={["main.ts", "schema.ts"]}>
<Section>
```ts
import { seed } from "drizzle-seed";
import * as schema from "./schema.ts";

const main = async () => {
    const titlesOfCourtesy = ["Ms.", "Mrs.", "Dr."];
    const unitsOnOrders = [0, 10, 20, 30, 50, 60, 70, 80, 100];
    const reorderLevels = [0, 5, 10, 15, 20, 25, 30];
    const quantityPerUnit = [
        "100 - 100 g pieces",
        "100 - 250 g bags",
        "10 - 200 g glasses",
        "10 - 4 oz boxes",
        "10 - 500 g pkgs.",
        "10 - 500 g pkgs."
    ];
    const discounts = [0.05, 0.15, 0.2, 0.25];

    await seed(db, schema).refine((funcs) => ({
        customers: {
            count: 10000,
            columns: {
                companyName: funcs.companyName(),
                contactName: funcs.fullName(),
                contactTitle: funcs.jobTitle(),
                address: funcs.streetAddress(),
                city: funcs.city(),
                postalCode: funcs.postcode(),
                region: funcs.state(),
                country: funcs.country(),
                phone: funcs.phoneNumber({ template: "(###) ###-####" }),
                fax: funcs.phoneNumber({ template: "(###) ###-####" })
            }
        },
        employees: {
            count: 200,
            columns: {
                firstName: funcs.firstName(),
                lastName: funcs.lastName(),
                title: funcs.jobTitle(),
                titleOfCourtesy: funcs.valuesFromArray({ values: titlesOfCourtesy }),
                birthDate: funcs.date({ minDate: "2010-12-31", maxDate: "2010-12-31" }),
                hireDate: funcs.date({ minDate: "2010-12-31", maxDate: "2024-08-26" }),
                address: funcs.streetAddress(),
                city: funcs.city(),
                postalCode: funcs.postcode(),
                country: funcs.country(),
                homePhone: funcs.phoneNumber({ template: "(###) ###-####" }),
                extension: funcs.int({ minValue: 428, maxValue: 5467 }),
                notes: funcs.loremIpsum()
            }
        },
        orders: {
            count: 50000,
            columns: {
                shipVia: funcs.int({ minValue: 1, maxValue: 3 }),
                freight: funcs.number({ minValue: 0, maxValue: 1000, precision: 100 }),
                shipName: funcs.streetAddress(),
                shipCity: funcs.city(),
                shipRegion: funcs.state(),
                shipPostalCode: funcs.postcode(),
                shipCountry: funcs.country()
            },
            with: {
                details:
                    [
                        { weight: 0.6, count: [1, 2, 3, 4] },
                        { weight: 0.2, count: [5, 6, 7, 8, 9, 10] },
                        { weight: 0.15, count: [11, 12, 13, 14, 15, 16, 17] },
                        { weight: 0.05, count: [18, 19, 20, 21, 22, 23, 24, 25] },
                    ]
            }
        },
        suppliers: {
            count: 1000,
            columns: {
                companyName: funcs.companyName(),
                contactName: funcs.fullName(),
                contactTitle: funcs.jobTitle(),
                address: funcs.streetAddress(),
                city: funcs.city(),
                postalCode: funcs.postcode(),
                region: funcs.state(),
                country: funcs.country(),
                phone: funcs.phoneNumber({ template: "(###) ###-####" })
            }
        },
        products: {
            count: 5000,
            columns: {
                name: funcs.companyName(),
                quantityPerUnit: funcs.valuesFromArray({ values: quantityPerUnit }),
                unitPrice: funcs.weightedRandom(
                    [
                        {
                            weight: 0.5,
                            value: funcs.int({ minValue: 3, maxValue: 300 })
                        },
                        {
                            weight: 0.5,
                            value: funcs.number({ minValue: 3, maxValue: 300, precision: 100 })
                        }
                    ]
                ),
                unitsInStock: funcs.int({ minValue: 0, maxValue: 125 }),
                unitsOnOrder: funcs.valuesFromArray({ values: unitsOnOrders }),
                reorderLevel: funcs.valuesFromArray({ values: reorderLevels }),
                discontinued: funcs.int({ minValue: 0, maxValue: 1 })
            }
        },
        details: {
            columns: {
                unitPrice: funcs.number({ minValue: 10, maxValue: 130 }),
                quantity: funcs.int({ minValue: 1, maxValue: 130 }),
                discount: funcs.weightedRandom(
                    [
                        { weight: 0.5, value: funcs.valuesFromArray({ values: discounts }) },
                        { weight: 0.5, value: funcs.default({ defaultValue: 0 }) }
                    ]
                )
            }
        }
    }));
}

main();

```
</Section>
<Section>
```ts
import type { AnyColumn } from "drizzle-orm";
import { integer, real, sqliteTable, text, integer, text } from "drizzle-orm/sqlite-core";

export const customers = sqliteTable('customer', {
	id: text({ length: 256 }).primaryKey(),
	companyName: text().notNull(),
	contactName: text().notNull(),
	contactTitle: text().notNull(),
	address: text().notNull(),
	city: text().notNull(),
	postalCode: text(),
	region: text(),
	country: text().notNull(),
	phone: text().notNull(),
	fax: text(),
});

export const employees = sqliteTable(
	'employee',
	{
		id: integer().primaryKey({ autoIncrement: true }),
		lastName: text().notNull(),
		firstName: text(),
		title: text().notNull(),
		titleOfCourtesy: text().notNull(),
		birthDate: integer().notNull(),
		hireDate: integer().notNull(),
		address: text().notNull(),
		city: text().notNull(),
		postalCode: text().notNull(),
		country: text().notNull(),
		homePhone: text().notNull(),
		extension: integer().notNull(),
		notes: text().notNull(),
		reportsTo: integer().references((): AnyColumn => employees.id),
		photoPath: text(),
	},
);

export const orders = sqliteTable('order', {
	id: integer().primaryKey({ autoIncrement: true }),
	orderDate: integer().notNull(),
	requiredDate: integer().notNull(),
	shippedDate: integer(),
	shipVia: integer().notNull(),
	freight: real().notNull(),
	shipName: text().notNull(),
	shipCity: text().notNull(),
	shipRegion: text(),
	shipPostalCode: text(),
	shipCountry: text().notNull(),

	customerId: text().notNull().references(() => customers.id, { onDelete: 'cascade' }),

	employeeId: integer().notNull().references(() => employees.id, { onDelete: 'cascade' }),
});

export const suppliers = sqliteTable('supplier', {
	id: integer().primaryKey({ autoIncrement: true }),
	companyName: text().notNull(),
	contactName: text().notNull(),
	contactTitle: text().notNull(),
	address: text().notNull(),
	city: text().notNull(),
	region: text(),
	postalCode: text().notNull(),
	country: text().notNull(),
	phone: text().notNull(),
});

export const products = sqliteTable('product', {
	id: integer().primaryKey({ autoIncrement: true }),
	name: text().notNull(),
	quantityPerUnit: text().notNull(),
	unitPrice: real().notNull(),
	unitsInStock: integer().notNull(),
	unitsOnOrder: integer().notNull(),
	reorderLevel: integer().notNull(),
	discontinued: integer().notNull(),

	supplierId: integer().notNull().references(() => suppliers.id, { onDelete: 'cascade' }),
});

export const details = sqliteTable('order_detail', {
	unitPrice: real().notNull(),
	quantity: integer().notNull(),
	discount: real().notNull(),

	orderId: integer().notNull().references(() => orders.id, { onDelete: 'cascade' }),

	productId: integer().notNull().references(() => products.id, { onDelete: 'cascade' }),
});

```
</Section>
</CodeTabs>

## Limitations

#### Types limitations for `with`

Due to certain TypeScript limitations and the current API in Drizzle, it is not possible to properly infer references between tables, especially when circular dependencies between tables exist.

This means the `with` option will display all tables in the schema, and you will need to manually select the one that has a one-to-many relationship

<Callout title='warning'>
The `with` option works for one-to-many relationships. For example, if you have one `user` and many `posts`, you can use users `with` posts, but you cannot use posts `with` users
</Callout>

#### Type limitations for the third parameter in Drizzle tables:

Currently, we do not have type support for the third parameter in Drizzle tables. While it will work at runtime, it will not function correctly at the type level


Source: https://orm.drizzle.team/docs/sqlite/seed-versioning

import Tab from "@mdx/Tab.astro";
import Tabs from "@mdx/Tabs.astro";
import Callout from "@mdx/Callout.astro";
import TableWrapper from "@mdx/TableWrapper.astro";

# Versioning

`drizzle-seed` uses versioning to manage outputs for static and dynamic data. To ensure true 
determinism, ensure that values remain unchanged when using the same `seed` number. If changes are made to 
static data sources or dynamic data generation logic, the version will be updated, allowing
you to choose between sticking with the previous version or using the latest.

You can upgrade to the latest `drizzle-seed` version for new features, such as additional
generators, while maintaining deterministic outputs with a previous version if needed. This
is particularly useful when you need to rely on existing deterministic data while accessing new functionality.

```ts
await seed(db, schema, { version: '2' });
```

## History
<TableWrapper>
|          api version  |   npm version    |     Changed generators                    |
|  :--------------      | :--------------  | :-------------                            |
|       `v1`            | `0.1.1`          |                                           |
|       `v2`	        | `0.2.1`          |`string()`, `interval({ isUnique: true })` |
|       `v3`            | `0.4.0`          |`hash generating function`    			   |
|       `v4 (LTS) `     | `1.0.0-beta.8`   |`uuid` 								       |
</TableWrapper>

<Callout collapsed="How it works under the hood?">
> This is not an actual API change; it is just an example of how we will proceed with `drizzle-seed` versioning.

For example, `lastName` generator was changed, and new version, `V2`, of this generator became available.

Later, `firstName` generator was changed, making `V3` version of this generator available.

|                  |       `V1`       |      `V2`       |   `V3(latest)`   |
| :--------------: | :--------------: | :-------------: | :--------------: |
| **LastNameGen**  | `LastNameGenV1`  | `LastNameGenV2` |                  |
| **FirstNameGen** | `FirstNameGenV1` |                 | `FirstNameGenV3` |


##### Use the `firstName` generator of version 3 and the `lastName` generator of version 2
```ts
await seed(db, schema);
```

If you are not ready to use latest generator version right away, you can specify max version to use

##### Use the `firstName` generator of version 1 and the `lastName` generator of version 2
```ts
await seed(db, schema, { version: '2' });
```

##### Use the `firstName` generator of version 1 and the `lastName` generator of version 1.
```ts
await seed(db, schema, { version: '1' });
```

</Callout>

## Version 2
#### Unique `interval` generator was changed

<Callout title='Reason for upgrade'>
An older version of the generator could produce intervals like `1 minute 60 seconds` and `2 minutes 0 seconds`, treating them as distinct intervals.
However, when the `1 minute 60 seconds` interval is inserted into a SQLite database, it is automatically converted to `2 minutes 0 seconds`. As a result, attempting to insert the `2 minutes 0 seconds` interval into a unique column afterwards will cause an error
</Callout>


You will be affected, if you use the unique `interval` generator in your seeding script, as shown in the script below:
```ts
import { blob, sqliteTable, text } from 'drizzle-orm/sqlite-core';
import { drizzle } from 'drizzle-orm/better-sqlite3';
import { seed } from 'drizzle-seed';

const intervals = sqliteTable('intervals', {
	interval1: text().unique(),
	interval2: text(),
	interval3: blob().unique(),
	interval4: blob(),
});

async function main() {
	const db = drizzle(process.env.DATABASE_URL!);

	await seed(db, { intervals }).refine((f) => ({
		intervals: {
			columns: {
				interval1: f.interval({ isUnique: true }),
				interval2: f.interval({ isUnique: true }),
				interval3: f.interval({ isUnique: true }),
				interval4: f.interval({ isUnique: true }),
			},
		},
	}));
}

main();

```

#### `string` generators were changed: both non-unique and unique

<Callout title='Reason to upgrade'>
Ability to generate a unique string based on the length of the text column (e.g., `varchar(20)`)
</Callout>

You will be affected, if your table includes a column of a text-like type with a maximum length parameter or a unique column of a text-like type:
```ts
import { drizzle } from 'drizzle-orm/better-sqlite3';
import { blob, sqliteTable, text } from 'drizzle-orm/sqlite-core';
import { seed } from "drizzle-seed";

const strings = sqliteTable('strings', {
	string1: text().unique(),
	string2: text({ length: 256 }),
	string3: text({ length: 256 }).unique(),
	string4: blob().unique(),
});

async function main() {
  const db = drizzle(process.env.DATABASE_URL!);

  await seed(db, { strings });
}

main();
```

You will be affected, if you use the `string` generator in your seeding script, as shown in the script below:
```ts
import { blob, sqliteTable, text } from 'drizzle-orm/sqlite-core';
import { drizzle } from 'drizzle-orm/better-sqlite3';
import { seed } from "drizzle-seed";

const strings = sqliteTable("strings", {
    string1: text().unique(),
	string2: text(),
	string3: text({ length: 256 }).unique(),
	string4: text({ length: 256 }),
	string5: text({ length: 256 }),
	string6: blob().unique(),
	string7: blob(),
});

async function main() {
	const db = drizzle(process.env.DATABASE_URL!);

	await seed(db, { strings }).refine((f) => ({
		strings: {
			columns: {
				string1: f.string({ isUnique: true }),
				string2: f.string({ isUnique: true }),
				string3: f.string({ isUnique: true }),
				string4: f.string({ isUnique: true }),
				string5: f.string(),
				string6: f.string({ isUnique: true }),
				string7: f.string({ isUnique: true }),
			},
		},
	}));
}

main();
```

## Version 3
#### `hash generating function was changed`

<Callout title='Reason to upgrade'>
The previous version of the hash generating function generated different hashes depending on whether Bun or Node.js was used, and hashes also varied across versions of Node.js.

The new hash generating function will generate the same hash regardless of the version of Node.js or Bun, resulting in deterministic data generation across all versions.
</Callout>

All generators will output different values compared to the previous version, even with the same seed number.

**Usage**
```ts
await seed(db, schema);
// or explicit
await seed(db, schema, { version: '3' });
```

**Switch to the old version**

The previous version of hash generating function is v1.
```ts
await seed(db, schema, { version: '1' });
```
To use the v2 generators while maintaining the v1 hash generating function:
```ts
await seed(db, schema, { version: '2' });
```

## Version 4
#### `uuid` generator was changed

<Callout title='Reason to upgrade'>
UUID values generated by the old version of the `uuid` generator fail Zod’s v4 UUID validation.

example
```ts
import { createSelectSchema } from 'drizzle-zod';
import { seed } from 'drizzle-seed';

await seed(db, { uuidTest: schema.uuidTest }, { count: 1 }).refine((funcs) => ({
		uuidTest: {
			columns: {
				col1: funcs.uuid()
			}
		}
	})
);

const uuidSelectSchema = createSelectSchema(schema.uuidTest);
const res = await db.select().from(schema.uuidTest);
// the line below will throw an error when using old version of uuid generator
uuidSelectSchema.parse(res[0]);
```
</Callout>

**Usage**
```ts
await seed(db, schema);
// or explicit
await seed(db, schema, { version: '4' });
```

**Switch to the old version**

The previous version of `uuid` generator is v1.
```ts
await seed(db, schema, { version: '1' });
```
To use the v2 generators while maintaining the v1 `uuid` generator:
```ts
await seed(db, schema, { version: '2' });
```
To use the v3 generators while maintaining the v1 `uuid` generator:
```ts
await seed(db, schema, { version: '3' });
```


Source: https://orm.drizzle.team/docs/sqlite/select

import CodeTabs from '@mdx/CodeTabs.astro';
import Callout from '@mdx/Callout.astro';
import Section from '@mdx/Section.astro';
import $count from '@mdx/$count-sqlite.mdx';

# SQL Select
Drizzle provides you the most SQL-like way to fetch data from your database, while remaining type-safe and composable.
It natively supports mostly every query feature and capability of every dialect,
and whatever it doesn't support yet, can be added by the user with the powerful [sql](/docs/sqlite/sql) operator.

For the following examples, let's assume you have a `users` table defined like this:

```typescript
import { sqliteTable, integer, text } from 'drizzle-orm/sqlite-core';

export const users = sqliteTable('users', {
  id: integer().primaryKey(),
  name: text().notNull(),
  age: integer(),
});
```

### Basic select
Select all rows from a table including all columns:

<Section>
```typescript
const result = await db.select().from(users);
/*
  {
    id: number;
    name: string;
    age: number | null;
  }[]
*/
```
```sql
select "id", "name", "age" from "users";
```
</Section>

Notice that the result type is inferred automatically based on the table definition, including columns nullability.

<Callout type="info">
Drizzle always explicitly lists columns in the `select` clause instead of using `select *`.<br />
This is required internally to guarantee the fields order in the query result, and is also generally considered a good practice.
</Callout>

### Partial select
In some cases, you might want to select only a subset of columns from a table.
You can do that by providing a selection object to the `.select()` method:
<Section>
```typescript copy
const result = await db.select({
  field1: users.id,
  field2: users.name,
}).from(users);

const { field1, field2 } = result[0];
```
```sql
select "id", "name" from "users";
```
</Section>

Like in SQL, you can use arbitrary expressions as selection fields, not just table columns:

<Section>
```typescript
const result = await db.select({
  id: users.id,
  lowerName: sql<string>`lower(${users.name})`,
}).from(users);
```
```sql
select "id", lower("name") from "users";
```
</Section>

<Callout type="warning">
By specifying `sql<string>`, you are telling Drizzle that the **expected** type of the field is `string`.<br />
If you specify it incorrectly (e.g. use `sql<number>` for a field that will be returned as a string), the runtime value won't match the expected type.
Drizzle cannot perform any type casts based on the provided type generic, because that information is not available at runtime.

If you need to apply runtime transformations to the returned value, you can use the [`.mapWith()`](/docs/sqlite/sql#sqlmapwith) method.
</Callout>

### Conditional select

You can have a dynamic selection object based on some condition:

```typescript
async function selectUsers(withName: boolean) {
  return db
    .select({
      id: users.id,
      ...(withName ? { name: users.name } : {}),
    })
    .from(users);
}

const result = await selectUsers(true);
```

### Distinct select

You can use `.selectDistinct()` instead of `.select()` to retrieve only unique rows from a dataset:
<Section>
```ts
await db.selectDistinct().from(users).orderBy(users.id, users.name);

await db.selectDistinct({ id: users.id }).from(users).orderBy(users.id);
```
```sql
select distinct "id", "name", "age" from "users" order by "users"."id", "users"."name";

select distinct "id" from "users" order by "users"."id";
```
</Section>

### Advanced select
Powered by TypeScript, Drizzle APIs let you build your select queries in a variety of flexible ways.

Sneak peek of advanced partial select, for more detailed advanced usage examples - see our [dedicated guide](/docs/sqlite/guides/include-or-exclude-columns).

<CodeTabs items={["example 1", "example 2", "example 3", "example 4"]}>
```ts
import { getColumns, sql } from 'drizzle-orm';

await db.select({
    ...getColumns(posts),
    titleLength: sql<number>`length(${posts.title})`,
  }).from(posts);
```
```ts
import { getColumns } from 'drizzle-orm';

const { content, ...rest } = getColumns(posts); // exclude "content" column
await db.select({ ...rest }).from(posts); // select all other columns
```
```ts
await db.query.posts.findMany({
  columns: {
    title: true,
  },
});
```
```ts
await db.query.posts.findMany({
  columns: {
    content: false,
  },
});
```
</CodeTabs>

## ---

### Filters

You can filter the query results using the [filter operators](/docs/sqlite/operators) in the `.where()` method:

<Section>
```typescript copy
import { eq, lt, gte, ne } from 'drizzle-orm';

await db.select().from(users).where(eq(users.id, 42));
await db.select().from(users).where(lt(users.id, 42));
await db.select().from(users).where(gte(users.id, 42));
await db.select().from(users).where(ne(users.id, 42));
...
```
```sql
select "id", "name", "age" from "users" where "users"."id" = 42;
select "id", "name", "age" from "users" where "users"."id" < 42;
select "id", "name", "age" from "users" where "users"."id" >= 42;
select "id", "name", "age" from "users" where "users"."id" <> 42;
```
</Section>

All filter operators are implemented using the [`sql`](/docs/sqlite/sql) function.
You can use it yourself to write arbitrary SQL filters, or build your own operators.
For inspiration, you can check how the operators provided by Drizzle are [implemented](https://github.com/drizzle-team/drizzle-orm/blob/main/drizzle-orm/src/sql/expressions/conditions.ts).
<Section>
```typescript copy
import { sql } from 'drizzle-orm';
import type { SQLiteColumn } from "drizzle-orm/sqlite-core";

function equals42(col: SQLiteColumn) {
  return sql`${col} = 42`;
}

await db.select().from(users).where(sql`${users.id} < 42`);
await db.select().from(users).where(sql`${users.id} = 42`);
await db.select().from(users).where(equals42(users.id));
await db.select().from(users).where(sql`${users.id} >= 42`);
await db.select().from(users).where(sql`${users.id} <> 42`);
await db.select().from(users).where(sql`lower(${users.name}) = 'aaron'`);
```
```sql
select "id", "name", "age" from "users" where "users"."id" < 42;
select "id", "name", "age" from "users" where "users"."id" = 42;
select "id", "name", "age" from "users" where "users"."id" = 42;
select "id", "name", "age" from "users" where "users"."id" >= 42;
select "id", "name", "age" from "users" where "users"."id" <> 42;
select "id", "name", "age" from "users" where lower("users"."name") = 'aaron';
```
</Section>

<Callout type='info'>
All the values provided to filter operators and to the `sql` function are parameterized automatically.
For example, this query:
```ts
await db.select().from(users).where(eq(users.id, 42));
```
will be translated to:
```sql
select "id", "name", "age" from "users" where "users"."id" = ?; -- params: [42]
```
</Callout>

Inverting condition with a `not` operator:
<Section>
```typescript copy
import { eq, not, sql } from 'drizzle-orm';

await db.select().from(users).where(not(eq(users.id, 42)));
await db.select().from(users).where(sql`not ${users.id} = 42`);
```
```sql
select "id", "name", "age" from "users" where not ("users"."id" = 42);
select "id", "name", "age" from "users" where not "users"."id" = 42;
```
</Section>

<Callout type="info">
You can safely alter schema, rename tables and columns
and it will be automatically reflected in your queries because of template interpolation,
as opposed to hardcoding column or table names when writing raw SQL.
</Callout>

### Combining filters
You can logically combine filter operators with `and()` and `or()` operators:
<Section>
```typescript copy
import { eq, and, sql } from 'drizzle-orm';

await db.select().from(users).where(
  and(
    eq(users.id, 42),
    eq(users.name, 'Dan')
  )
);
await db.select().from(users).where(sql`${users.id} = 42 and ${users.name} = 'Dan'`);
```
```sql
select "id", "name", "age" from "users" where (("users"."id" = 42) and ("users"."name" = 'Dan'));
select "id", "name", "age" from "users" where "users"."id" = 42 and "users"."name" = 'Dan';
```
</Section>

<Section>
```typescript copy
import { eq, or, sql } from 'drizzle-orm';

await db.select().from(users).where(
  or(
    eq(users.id, 42), 
    eq(users.name, 'Dan')
  )
);
await db.select().from(users).where(sql`${users.id} = 42 or ${users.name} = 'Dan'`);
```
```sql
select "id", "name", "age" from "users" where (("users"."id" = 42) or ("users"."name" = 'Dan'));
select "id", "name", "age" from "users" where "users"."id" = 42 or "users"."name" = 'Dan';
```
</Section>

### Advanced filters
In combination with TypeScript, Drizzle APIs provide you powerful and flexible ways to combine filters in queries.

Sneak peek of conditional filtering, for more detailed advanced usage examples - see our [dedicated guide](/docs/sqlite/guides/conditional-filters-in-query).
<CodeTabs items={["example 1", "example 2"]}>
```ts
const searchPosts = async (term?: string) => {
  await db
    .select()
    .from(posts)
    .where(term ? like(posts.title, term) : undefined);
};
await searchPosts();
await searchPosts('AI');
```
```ts
const searchPosts = async (filters: SQL[]) => {
  await db
    .select()
    .from(posts)
    .where(and(...filters));
};
const filters: SQL[] = [];
filters.push(like(posts.title, 'AI'));
filters.push(inArray(posts.category, ['Tech', 'Art', 'Science']));
filters.push(gt(posts.views, 200));
await searchPosts(filters);
```
</CodeTabs>

## ---

### Limit & offset
Use `.limit()` and `.offset()` to add limit and offset clauses to the query - for example, to implement pagination:

```ts
await db.select().from(users).limit(10);
await db.select().from(users).limit(10).offset(10);
```

```sql
select "id", "name", "age" from "users" limit 10;
select "id", "name", "age" from "users" limit 10 offset 10;
```

### Order By
Use `.orderBy()` to add `order by` clause to the query, sorting the results by the specified fields:
<Section>
```typescript
import { asc, desc } from 'drizzle-orm';

await db.select().from(users).orderBy(users.name);
await db.select().from(users).orderBy(desc(users.name));

// order by multiple fields
await db.select().from(users).orderBy(users.name, users.name2);
await db.select().from(users).orderBy(asc(users.name), desc(users.name2));
```
```sql
select "id", "name", "name2", "age" from "users" order by "users"."name";
select "id", "name", "name2", "age" from "users" order by "users"."name" desc;

select "id", "name", "name2", "age" from "users" order by "users"."name", "users"."name";
select "id", "name", "name2", "age" from "users" order by "users"."name" asc, "users"."name2" desc;
```
</Section>

### Advanced pagination
Powered by TypeScript, Drizzle APIs let you implement all possible SQL pagination and sorting approaches.

Sneak peek of advanced pagination, for more detailed advanced
usage examples - see our dedicated [limit offset pagination](/docs/sqlite/guides/limit-offset-pagination)
and [cursor pagination](/docs/sqlite/guides/cursor-based-pagination) guides.

<CodeTabs items={["example 1", "example 2", "example 3", "example 4"]}>
```ts
await db
  .select()
  .from(users)
  .orderBy(asc(users.id)) // order by is mandatory
  .limit(4) // the number of rows to return
  .offset(4); // the number of rows to skip
```
```ts
const getUsers = async (page = 1, pageSize = 3) => {
  return await db.query.users.findMany({
    orderBy: (users, { asc }) => asc(users.id),
    limit: pageSize,
    offset: (page - 1) * pageSize,
  });
};
await getUsers();
```
```ts
const getUsers = async (page = 1, pageSize = 10) => {
   const sq = db
    .select({ id: users.id })
    .from(users)
    .orderBy(users.id)
    .limit(pageSize)
    .offset((page - 1) * pageSize)
    .as('subquery');
   return await db.select().from(users).innerJoin(sq, eq(users.id, sq.id)).orderBy(users.id);
};
```
```ts
const nextUserPage = async (cursor?: number, pageSize = 3) => {
  return await db
    .select()
    .from(users)
    .where(cursor ? gt(users.id, cursor) : undefined) // if cursor is provided, get rows after it
    .limit(pageSize) // the number of rows to return
    .orderBy(asc(users.id)); // ordering
};
// pass the cursor of the last row of the previous page (id)
await nextUserPage(3);
```
</CodeTabs>

## ---

### WITH clause

<Callout>
  Check how to use WITH statement with [insert](/docs/sqlite/insert#with-insert-clause), [update](/docs/sqlite/update#with-update-clause), [delete](/docs/sqlite/delete#with-delete-clause)
</Callout>

Using the `with` clause can help you simplify complex queries by splitting them into smaller subqueries called common table expressions (CTEs):
<Section>
```typescript copy
const sq = db.$with('sq').as(db.select().from(users).where(eq(users.id, 42)));

const result = await db.with(sq).select().from(sq);
```
```sql
with "sq" as (select "id", "name", "age" from "users" where "users"."id" = 42)
select "id", "name", "age" from "sq";
```
</Section>

You can also provide `insert`, `update` and `delete` statements inside `with`

<Section>
```typescript copy
const sq = db.$with('sq').as(
    db.insert(users).values({ name: 'John' }).returning(),
);

const result = await db.with(sq).select().from(sq);
```
</Section>

<Section>
```typescript copy
const sq = db.$with('sq').as(
    db.update(users).set({ age: 25 }).where(eq(users.name, 'John')).returning(),
);
const result = await db.with(sq).select().from(sq);
```
</Section>

<Section>
```typescript copy
const sq = db.$with('sq').as(
  db.delete(users).where(eq(users.name, 'John')).returning(),
);

const result = await db.with(sq).select().from(sq);
```
</Section>

To select arbitrary SQL values as fields in a CTE and reference them in other CTEs or in the main query,
you need to add aliases to them:
```typescript copy
const sq = db.$with('sq').as(db.select({ 
  name: sql<string>`upper(${users.name})`.as('name'),
})
.from(users));

const result = await db.with(sq).select({ name: sq.name }).from(sq);
```
If you don't provide an alias, the field type will become `DrizzleTypeError` and you won't be able to reference it in other queries.
If you ignore the type error and still try to use the field,
you will get a runtime error, since there's no way to reference that field without an alias.

### Select from subquery
Just like in SQL, you can embed queries into other queries by using the subquery API:
<Section>
```typescript copy
const sq = db.select().from(users).where(eq(users.id, 42)).as('sq');
const result = await db.select().from(sq);
```
```sql
select "id", "name", "age" from (select "id", "name", "age" from "users" where "users"."id" = 42) "sq";
```
</Section>

Subqueries can be used in any place where a table can be used, for example in joins:
<Section>
```typescript copy
const sq = db.select().from(users).where(eq(users.id, 42)).as('sq');
const result = await db.select().from(users).leftJoin(sq, eq(users.id, sq.id));
```
```sql
select "users"."id", "users"."name", "users"."age", "sq"."id", "sq"."name", "sq"."age" from "users"
  left join (select "id", "name", "age" from "users" where "users"."id" = 42) "sq"
    on "users"."id" = "sq"."id";
```
</Section>

## ---

### Aggregations
With Drizzle, you can do aggregations using functions like `sum`, `count`, `avg`, etc. by
grouping and filtering with `.groupBy()` and `.having()` respectfully, same as you would do in raw SQL:

<Section>
```typescript
import { gt, sql } from "drizzle-orm";

await db.select({
  age: users.age,
  count: sql<number>`cast(count(${users.id}) as int)`,
})
  .from(users)
  .groupBy(users.age);

await db.select({
  age: users.age,
  count: sql<number>`cast(count(${users.id}) as int)`,
})
  .from(users)
  .groupBy(users.age)
  .having(({ count }) => gt(count, 1));
```
```sql
select "age", cast(count("id") as int)
  from "users"
  group by "users"."age";

select "age", cast(count("id") as int)
  from "users"
  group by "users"."age"
  having cast(count("users"."id") as int) > 1;
```
</Section>

<Callout type="info">
`cast(... as int)` keeps the selected count value typed as a number.
Alternatively, you can use [`.mapWith(Number)`](/docs/sqlite/sql#sqlmapwith) to cast the value to a number at runtime.

If you need count aggregation - we recommend using our [$count](/docs/sqlite/select#count) API
</Callout>

### Aggregations helpers

Drizzle has a set of wrapped `sql` functions, so you don't need to write
`sql` templates for common cases in your app

<Callout type="info">
 Remember, aggregation functions are often used with the GROUP BY clause of the SELECT statement. 
 So if you are selecting using aggregating functions and other columns in one query, 
 be sure to use the `.groupBy` clause
</Callout>

**count**

Returns the number of values in `expression`.
<Section>
```ts
import { count } from 'drizzle-orm'

await db.select({ value: count() }).from(users);
await db.select({ value: count(users.id) }).from(users);
```
```sql
select count(*) from "users";
select count("id") from "users";
```
```ts
// It's equivalent to writing
await db.select({ 
  value: sql`count(*)`.mapWith(Number) 
}).from(users);

await db.select({ 
  value: sql`count(${users.id})`.mapWith(Number) 
}).from(users);
```
</Section>

**countDistinct**

Returns the number of non-duplicate values in `expression`.
<Section>
```ts
import { countDistinct } from 'drizzle-orm'

await db.select({ value: countDistinct(users.id) }).from(users);
```
```sql
select count(distinct "id") from "users";
```
```ts
// It's equivalent to writing
await db.select({ 
  value: sql`count(distinct ${users.id})`.mapWith(Number) 
}).from(users);
```
</Section>

**avg**

Returns the average (arithmetic mean) of all non-null values in `expression`.
<Section>
```ts
import { avg } from 'drizzle-orm'

await db.select({ value: avg(users.id) }).from(users);
```
```sql
select avg("id") from "users";
```
```ts
// It's equivalent to writing
await db.select({ 
  value: sql`avg(${users.id})`.mapWith(String) 
}).from(users);
```
</Section>

**avgDistinct**

Returns the average (arithmetic mean) of all non-null values in `expression`.
<Section>
```ts
import { avgDistinct } from 'drizzle-orm'

await db.select({ value: avgDistinct(users.id) }).from(users);
```
```sql
select avg(distinct "id") from "users";
```
```ts
// It's equivalent to writing
await db.select({ 
  value: sql`avg(distinct ${users.id})`.mapWith(String) 
}).from(users);
```
</Section>

**sum**

Returns the sum of all non-null values in `expression`.
<Section>
```ts
import { sum } from 'drizzle-orm'

await db.select({ value: sum(users.id) }).from(users);
```
```sql
select sum("id") from "users";
```
```ts
// It's equivalent to writing
await db.select({ 
  value: sql`sum(${users.id})`.mapWith(String) 
}).from(users);
```
</Section>

**sumDistinct**

Returns the sum of all non-null and non-duplicate values in `expression`.
<Section>
```ts
import { sumDistinct } from 'drizzle-orm'

await db.select({ value: sumDistinct(users.id) }).from(users);
```
```sql
select sum(distinct "id") from "users";
```
```ts
// It's equivalent to writing
await db.select({ 
  value: sql`sum(distinct ${users.id})`.mapWith(String) 
}).from(users);
```
</Section>

**max**

Returns the maximum value in `expression`.
<Section>
```ts
import { max } from 'drizzle-orm'

await db.select({ value: max(users.id) }).from(users);
```
```sql
select max("id") from "users";
```
```ts
// It's equivalent to writing
await db.select({ 
  value: sql`max(${expression})`.mapWith(users.id) 
}).from(users);
```
</Section>

**min**

Returns the minimum value in `expression`.
<Section>
```ts
import { min } from 'drizzle-orm'

await db.select({ value: min(users.id) }).from(users);
```
```sql
select min("id") from "users";
```
```ts
// It's equivalent to writing
await db.select({ 
  value: sql`min(${users.id})`.mapWith(users.id) 
}).from(users);
```
</Section>

A more advanced example:

```typescript copy
const orders = sqliteTable('order', {
  id: integer('id').primaryKey(),
  orderDate: integer('order_date', { mode: 'timestamp' }).notNull(),
  requiredDate: integer('required_date', { mode: 'timestamp' }).notNull(),
  shippedDate: integer('shipped_date', { mode: 'timestamp' }),
  shipVia: integer('ship_via').notNull(),
  freight: numeric('freight').notNull(),
  shipName: text('ship_name').notNull(),
  shipCity: text('ship_city').notNull(),
  shipRegion: text('ship_region'),
  shipPostalCode: text('ship_postal_code'),
  shipCountry: text('ship_country').notNull(),
  customerId: text('customer_id').notNull(),
  employeeId: integer('employee_id').notNull(),
});

const details = sqliteTable('order_detail', {
  unitPrice: numeric('unit_price').notNull(),
  quantity: integer('quantity').notNull(),
  discount: numeric('discount').notNull(),
  orderId: integer('order_id').notNull(),
  productId: integer('product_id').notNull(),
});


db
  .select({
    id: orders.id,
    shippedDate: orders.shippedDate,
    shipName: orders.shipName,
    shipCity: orders.shipCity,
    shipCountry: orders.shipCountry,
    productsCount: sql<number>`cast(count(${details.productId}) as int)`,
    quantitySum: sql<number>`sum(${details.quantity})`,
    totalPrice: sql<number>`sum(${details.quantity} * ${details.unitPrice})`,
  })
  .from(orders)
  .leftJoin(details, eq(orders.id, details.orderId))
  .groupBy(orders.id)
  .orderBy(asc(orders.id))
  .all();
```

### $count

<$count/>


Source: https://orm.drizzle.team/docs/sqlite/set-operations

import CodeTabs from '@mdx/CodeTabs.astro';
import CodeTab from '@mdx/CodeTab.astro';
import Callout from '@mdx/Callout.astro';

# Set Operations

SQL set operations combine the results of multiple query blocks into a single result. 
The SQL standard defines the following three set operations: `UNION`, `INTERSECT`, `EXCEPT`, `UNION ALL`, `INTERSECT ALL`, `EXCEPT ALL`.

### Union
Combine all results from two query blocks into a single result, omitting any duplicates.

Get all names from customers and users tables without duplicates.

<CodeTabs items={["import-pattern", "builder-pattern", "schema.ts"]}>
	<CodeTab>
	```typescript copy
    import { union } from 'drizzle-orm/sqlite-core'
    import { users, customers } from './schema'

    const allNamesForUserQuery = db.select({ name: users.name }).from(users);

    const result = await union(
		allNamesForUserQuery,
		db.select({ name: customers.name }).from(customers)
	).limit(10);
    ```
    ```sql
    (select "name" from "sellers")
    union 
    (select "name" from "customers")
    limit 10
    ```
	</CodeTab>
    <CodeTab>
    ```ts copy
    import { users, customers } from './schema'

    const result = await db
      .select({ name: users.name })
      .from(users)
      .union(db.select({ name: customers.name }).from(customers))
      .limit(10);
    ```
    ```sql
    select "name" from "sellers" union select "name" from "customers" limit 10
    ```
    </CodeTab>
    <CodeTab>
	```typescript copy
    import { int, sqliteTable, text } from "drizzle-orm/sqlite-core";

    const users = sqliteTable('sellers', {
        id: int().primaryKey(),
        name: text().notNull(),
        address: text(),
    });
    
    const customers = sqliteTable('customers', {
        id: int().primaryKey(),
        name: text().notNull(),
        city: text(),
        email: text().notNull()
    });
    ```
    </CodeTab>
  </CodeTabs>

### Union All
Combine all results from two query blocks into a single result, with duplicates.

Let's consider a scenario where you have two tables, one representing online sales and the other 
representing in-store sales. In this case, you want to combine the data from both tables into a
single result set. Since there might be duplicate transactions, 
you want to keep all the records and not eliminate duplicates.

<CodeTabs items={["import-pattern", "builder-pattern", "schema.ts"]}>
	<CodeTab>
	```typescript copy
    import { unionAll } from 'drizzle-orm/sqlite-core'
    import { onlineSales, inStoreSales } from './schema'

    const onlineTransactions = db.select({ transaction: onlineSales.transactionId }).from(onlineSales);
    const inStoreTransactions = db.select({ transaction: inStoreSales.transactionId }).from(inStoreSales);

    const result = await unionAll(onlineTransactions, inStoreTransactions);
    ```
    ```sql
    select "transaction_id" from "online_sales" 
    union all 
    select "transaction_id" from "in_store_sales"
    ```
    </CodeTab>
    <CodeTab>
    ```ts copy
    import { onlineSales, inStoreSales } from './schema'

    const result = await db
      .select({ transaction: onlineSales.transactionId })
      .from(onlineSales)
      .unionAll(
        db.select({ transaction: inStoreSales.transactionId }).from(inStoreSales)
      );
    ```
    ```sql
    select "transaction_id" from "online_sales" 
    union all 
    select "transaction_id" from "in_store_sales"
    ```
	</CodeTab>
    <CodeTab>
	```typescript copy
    import { int, sqliteTable } from "drizzle-orm/sqlite-core";

    const onlineSales = sqliteTable('online_sales', {
        transactionId: int('transaction_id').primaryKey(),
        productId: int('product_id').unique(),
        quantitySold: int('quantity_sold'),
        saleDate: int('sale_date', { mode: 'timestamp' }),
    });
    
    const inStoreSales = sqliteTable('in_store_sales', {
        transactionId: int('transaction_id').primaryKey(),
        productId: int('product_id').unique(),
        quantitySold: int('quantity_sold'),
        saleDate: int('sale_date', { mode: 'timestamp' }),
    });
    ```
    </CodeTab>
  </CodeTabs>

### Intersect
Combine only those rows which the results of two query blocks have in common, omitting any duplicates.

Suppose you have two tables that store information about students' course enrollments. 
You want to find the courses that are common between two different departments,
but you want distinct course names, and you're not interested in counting multiple 
enrollments of the same course by the same student.

In this scenario, you want to find courses that are common between the two departments but don't want 
to count the same course multiple times even if multiple students from the same department are enrolled in it.

<CodeTabs items={["import-pattern", "builder-pattern", "schema.ts"]}>
	<CodeTab>
	```typescript copy
    import { intersect } from 'drizzle-orm/sqlite-core'
    import { depA, depB } from './schema'

    const departmentACourses = db.select({ courseName: depA.courseName }).from(depA);
    const departmentBCourses = db.select({ courseName: depB.courseName }).from(depB);

    const result = await intersect(departmentACourses, departmentBCourses);
    ```
    ```sql
    select "course_name" from "department_a_courses"
    intersect
    select "course_name" from "department_b_courses"
    ```
	</CodeTab>
    <CodeTab>
    ```typescript copy
    import { depA, depB } from './schema'

    const result = await db
      .select({ courseName: depA.courseName })
      .from(depA)
      .intersect(db.select({ courseName: depB.courseName }).from(depB));
    ```
    ```sql
    select "course_name" from "department_a_courses" 
    intersect 
    select "course_name" from "department_b_courses"
    ```
    </CodeTab>
    <CodeTab>
	```typescript copy
    import { int, sqliteTable, text } from "drizzle-orm/sqlite-core";

    const depA = sqliteTable('department_a_courses', {
        studentId: int('student_id'),
        courseName: text('course_name').notNull(),
    });
    
    const depB = sqliteTable('department_b_courses', {
        studentId: int('student_id'),
        courseName: text('course_name').notNull(),
    });
    ```
    </CodeTab>
  </CodeTabs>

### Intersect All
Combine only those rows which the results of two query blocks have in common, with duplicates.

Let's consider a scenario where you have two tables containing data about customer orders, and you want 
to identify products that are ordered by both regular customers and VIP customers. In this case, 
you want to keep track of the quantity of each product, even if it's ordered multiple times by 
different customers.

In this scenario, you want to find products that are ordered by both regular customers and VIP customers, 
but you want to retain the quantity information, even if the same product is ordered multiple 
times by different customers.

Not supported by SQLite

### Except
For two query blocks A and B, return all results from A which are not also present in B, omitting any duplicates.

Suppose you have two tables that store information about employees' project assignments. 
You want to find the projects that are unique to one department 
and not shared with another department, excluding duplicates.

In this scenario, you want to identify the projects that are exclusive to one department and
not shared with the other department. You don't want to count the same project 
multiple times, even if multiple employees from the same department are assigned to it.

<CodeTabs items={["import-pattern", "builder-pattern", "schema.ts"]}>
	<CodeTab>
	```typescript copy
    import { except } from 'drizzle-orm/sqlite-core'
    import { depA, depB } from './schema'

    const departmentACourses = db.select({ courseName: depA.projectsName }).from(depA);
    const departmentBCourses = db.select({ courseName: depB.projectsName }).from(depB);

    const result = await except(departmentACourses, departmentBCourses);
    ```
    ```sql
    select "projects_name" from "department_a_projects" 
    except 
    select "projects_name" from "department_b_projects"
    ```
	</CodeTab>
    <CodeTab>
    ```ts copy
    import { depA, depB } from './schema'

    const result = await db
        .select({ courseName: depA.projectsName })
        .from(depA)
        .except(db.select({ courseName: depB.projectsName }).from(depB));
    ```
    ```sql
    select "projects_name" from "department_a_projects" 
    except 
    select "projects_name" from "department_b_projects"
    ```
    </CodeTab>
    <CodeTab>
	```typescript copy
    import { int, sqliteTable, text } from "drizzle-orm/sqlite-core";

    const depA = sqliteTable('department_a_projects', {
        employeeId: int('employee_id'),
        projectsName: text('projects_name').notNull(),
    });
    
    const depB = sqliteTable('department_b_projects', {
        employeeId: int('employee_id'),
        projectsName: text('projects_name').notNull(),
    });
    ```
    </CodeTab>
  </CodeTabs>

### Except All
For two query blocks A and B, return all results from A which are not also present in B, with duplicates.

Let's consider a scenario where you have two tables containing data about customer orders, and you want to 
identify products that are exclusively ordered by regular customers (without VIP customers). 
In this case, you want to keep track of the quantity of each product, even if it's ordered multiple times by different regular customers.

In this scenario, you want to find products that are exclusively ordered by regular customers and not 
ordered by VIP customers. You want to retain the quantity information, even if the same product is ordered multiple times by different regular customers.

Not supported by SQLite


Source: https://orm.drizzle.team/docs/sqlite/sql-schema-declaration

import Callout from '@mdx/Callout.astro';
import SimpleLinkCards from '@mdx/SimpleLinkCards.astro';
import CodeTabs from "@mdx/CodeTabs.astro";
import Section from '@mdx/Section.astro';
import Flex from "@mdx/Flex.astro"
import LinksList from "@mdx/LinksList.astro"

# Drizzle schema

Drizzle lets you define a schema in TypeScript with various models and properties supported by the underlying database. 
When you define your schema, it serves as the source of truth for future modifications in queries (using Drizzle-ORM)
and migrations (using Drizzle-Kit).

<Callout> 
If you are using Drizzle-Kit for the migration process, make sure to export all the models defined in your schema files so that Drizzle-Kit can import them and use them in the migration diff process. 
</Callout>

<CodeTabs items={["Using imports", "Using callback", "Using import *"]}>
```ts
import { integer, sqliteTable, text } from "drizzle-orm/sqlite-core";

export const usersTable = sqliteTable("users", {
  id: integer().primaryKey({ autoIncrement: true }),
  name: text().notNull(),
  age: integer().notNull(),
  email: text().notNull().unique(),
});
```
```ts
import { sqliteTable } from "drizzle-orm/sqlite-core";

export const usersTable = sqliteTable("users", (t) => ({
  id: t.integer().primaryKey({ autoIncrement: true }),
  name: t.text().notNull(),
  age: t.integer().notNull(),
  email: t.text().notNull().unique(),
}));
```
```ts
import * as t from "drizzle-orm/sqlite-core";

export const usersTable = t.sqliteTable("users", {
  id: t.integer().primaryKey({ autoIncrement: true }),
  name: t.text().notNull(),
  age: t.integer().notNull(),
  email: t.text().notNull().unique(),
});
```
</CodeTabs>

## Organize your schema files 
You can declare your SQL schema directly in TypeScript either in a single `schema.ts` file,
or you can spread them around — whichever you prefer, all the freedom!

#### Schema in 1 file
The most common way to declare your schema with Drizzle is to put all your tables into one `schema.ts` file.

> Note: You can name your schema file whatever you like. For example, it could be `models.ts`, or something else.

This approach works well if you don't have too many table models defined, or if you're okay with keeping them all in one file

Example:
```plaintext
📦 <project root>
 └ 📂 src
    └ 📂 db
       └ 📜 schema.ts
```

In the `drizzle.config.ts` file, you need to specify the path to your schema file. With this configuration, Drizzle will 
read from the `schema.ts` file and use this information during the migration generation process. For more information 
about the `drizzle.config.ts` file and migrations with Drizzle, please check: [link](/docs/sqlite/drizzle-config-file)
```ts
import { defineConfig } from "drizzle-kit";

export default defineConfig({
  dialect: 'sqlite',
  schema: './src/db/schema.ts'
})
```

#### Schema in multiple files

You can place your Drizzle models — such as tables, enums, sequences, etc. — not only in one file but in any file you prefer. 
The only thing you must ensure is that you export all the models from those files so that the Drizzle kit can import 
them and use them in migrations.

One use case would be to separate each table into its own file.
```plaintext
📦 <project root>
 └ 📂 src
    └ 📂 db
       └ 📂 schema
          ├ 📜 users.ts
          ├ 📜 countries.ts
          ├ 📜 cities.ts
          ├ 📜 products.ts
          ├ 📜 clients.ts
          └ 📜 etc.ts
```

In the `drizzle.config.ts` file, you need to specify the path to your schema folder. With this configuration, Drizzle will 
read from the `schema` folder and find all the files recursively and get all the drizzle tables from there. For more information 
about the `drizzle.config.ts` file and migrations with Drizzle, please check: [link](/docs/sqlite/drizzle-config-file)

```ts
import { defineConfig } from "drizzle-kit";

export default defineConfig({
  dialect: 'sqlite',
  schema: './src/db/schema'
})
```

You can also group them in any way you like, such as creating groups for user-related tables, messaging-related tables, product-related tables, etc. 
```plaintext
📦 <project root>
 └ 📂 src
    └ 📂 db
       └ 📂 schema
          ├ 📜 users.ts
          ├ 📜 messaging.ts
          └ 📜 products.ts
```

## Shape your data schema

Drizzle schema consists of several model types from database you are using. With drizzle you can specify:
- Tables with columns, constraints, etc.
- Views
- etc.

Let's go one by one and check how the schema should be defined with drizzle

#### **Tables and columns declaration** 

A table in Drizzle should be defined with at least 1 column, the same as it should be done in database. There is one important thing to know,
there is no such thing as a common table object in Drizzle. You need to choose a dialect you are using, PostgreSQL, MySQL, SQLite, etc.

![](@/assets/images/table-structure.svg)

```ts copy
import { sqliteTable, integer } from "drizzle-orm/sqlite-core"

export const users = sqliteTable('users', {
  id: integer()
});
```

By default, Drizzle will use the TypeScript key names for columns in database queries. 
Therefore, the schema and query from the example will generate the SQL query shown below

<Callout>
This example uses a db object, whose initialization is not covered in this part of the documentation. To learn how to connect to the database, please refer to the [Connections Docs](/docs/sqlite/get-started-sqlite)
</Callout>

\
**TypeScript key = database key**
<Section>
```ts
// schema.ts
import { integer, sqliteTable, text } from "drizzle-orm/sqlite-core";

export const users = sqliteTable('users', {
  id: integer(),
  first_name: text()
})
```
```ts
// query.ts
await db.select().from(users);
```
```sql
SELECT "id", "first_name" from users;
```
</Section>

If you want to use different names in your TypeScript code and in the database, you can use column aliases

<Section>
```ts
// schema.ts
import { integer, sqliteTable, text } from "drizzle-orm/sqlite-core";

export const users = sqliteTable('users', {
  id: integer(),
  firstName: text('first_name')
})
```
```ts
// query.ts
await db.select().from(users);
```
```sql
SELECT "id", "first_name" from users;
```
</Section>

### Camel and Snake casing

Database model names often use `snake_case` conventions, while in TypeScript, it is common to use `camelCase` for naming models.
This can lead to a lot of alias definitions in the schema. To address this, Drizzle provides a way to automatically
map `camelCase` from TypeScript to `snake_case` in the database via a dedicated builder.

Use the `snakeCase` or `camelCase` builder from `drizzle-orm/pg-core` to declare a table whose column keys are
automatically mapped to the chosen database naming convention

<Section>
```ts {2,4,11,12}
// schema.ts
import { snakeCase, camelCase } from 'drizzle-orm/sqlite-core';

export const users = snakeCase.table('users', {
  id: integer().primaryKey(),
  fullName: text(),        // → full_name in DB
  createdAt: integer({ mode: 'timestamp' }),  // → created_at in DB
});

// Available on all entity types:
snakeCase.table / snakeCase.view
camelCase.table / camelCase.view
```
```ts
// db.ts
import { drizzle } from "drizzle-orm/better-sqlite3";

const db = drizzle({ connection: process.env.DATABASE_URL })
```
```ts
// query.ts
await db.select().from(users);
```
```sql
select "id", "full_name", "created_at" from "users";
```
</Section>

### Advanced

There are a few tricks you can use with Drizzle ORM. As long as Drizzle is entirely in TypeScript files, 
you can essentially do anything you would in a simple TypeScript project with your code.

One common feature is to separate columns into different places and then reuse them. 
For example, consider the `updated_at`, `created_at`, and `deleted_at` columns. Many tables/models may need these 
three fields to track and analyze the creation, deletion, and updates of entities in a system

We can define those columns in a separate file and then import and spread them across all the table objects you have

<Section>
```ts
// columns.helpers.ts
export const timestamps = {
  updated_at: text(),
  created_at: text().$defaultFn(() => new Date().toISOString()).notNull(),
  deleted_at: text(),
}
```
```ts
// users.sql.ts
export const users = sqliteTable('users', {
  id: integer(),
  ...timestamps
})
```
```ts
// posts.sql.ts
export const posts = sqliteTable('posts', {
  id: integer(),
  ...timestamps
})
```
</Section>

#### **Schemas**

\
In SQLite, there is no concept of a schema, so you can only define tables within a single SQLite file context

![](@/assets/images/sqlite-db-structure.png)

### Example

Once you know the basics, let's define a schema example for a real project to get a better view and understanding

> All examples will use `generateUniqueString`. The implementation for it will be provided after all the schema examples

```ts copy
import * as t from "drizzle-orm/sqlite-core";

export const users = t.sqliteTable(
  "users",
  {
    id: t.integer().primaryKey({ autoIncrement: true }),
    firstName: t.text("first_name"),
    lastName: t.text("last_name"),
    email: t.text().notNull(),
    invitee: t.integer().references((): t.AnySQLiteColumn => users.id),
    role: t.text().$type<"guest" | "user" | "admin">().default("guest"),
  },
  (table) => [
    t.uniqueIndex("email_idx").on(table.email)
  ]
);

export const posts = t.sqliteTable(
  "posts",
  {
    id: t.integer().primaryKey({ autoIncrement: true }),
    slug: t.text().$default(() => generateUniqueString(16)),
    title: t.text(),
    ownerId: t.integer("owner_id").references(() => users.id),
  },
  (table) => [
    t.uniqueIndex("slug_idx").on(table.slug),
    t.index("title_idx").on(table.title),
  ]
);

export const comments = t.sqliteTable("comments", {
  id: t.integer().primaryKey({ autoIncrement: true }),
  text: t.text({ length: 256 }),
  postId: t.integer("post_id").references(() => posts.id),
  ownerId: t.integer("owner_id").references(() => users.id),
});
```

**`generateUniqueString` implementation:**
```ts
function generateUniqueString(length: number = 12): string {
  const characters =
    "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
  let uniqueString = "";

  for (let i = 0; i < length; i++) {
    const randomIndex = Math.floor(Math.random() * characters.length);
    uniqueString += characters[randomIndex];
  }

  return uniqueString;
}
```

#### What's next?
<br/>
<Flex>
  <LinksList 
    title='Manage schema'
    links={[
        ["Column types", "/docs/sqlite/column-types"], 
        ["Indexes and Constraints", "/docs/sqlite/indexes-constraints"],
        ["Database Views", "/docs/sqlite/views"],
      ]}
  />
  <LinksList 
    title='Zero to Hero'
    links={[
        ["Database connection", "/docs/sqlite/connect-overview"], 
        ["Data querying", "/docs/sqlite/data-querying"], 
        ["Migrations", "/docs/sqlite/migrations"], 
      ]}
  />
</Flex>


Source: https://orm.drizzle.team/docs/sqlite/sql

import Callout from '@mdx/Callout.astro';
import Section from '@mdx/Section.astro';

# Magical `sql` operator 🪄

When working with an ORM library, there may be cases where you find it challenging to write a
specific query using the provided ORM syntax. In such situations, you can resort to using
raw queries, which involve constructing a query as a raw string. However, raw queries often
lack the benefits of type safety and query parameterization.

To address this, many libraries have introduced the concept of an `sql` template. This template 
allows you to write more type-safe and parameterized queries, enhancing the overall safety and 
flexibility of your code. Drizzle, being a powerful ORM library, also supports the sql template.

With Drizzle's `sql` template, you can go even further in crafting queries. If you encounter 
difficulties in writing an entire query using the library's query builder, you can selectively
use the `sql` template within specific sections of the Drizzle query. This flexibility enables you 
to employ the sql template in partial SELECT statements, WHERE clauses, ORDER BY clauses, HAVING
clauses, GROUP BY clauses, and even in relational query builders.

By leveraging the capabilities of the sql template in Drizzle, you can maintain the advantages 
of type safety and query parameterization while achieving the desired query structure and complexity.
This empowers you to create more robust and maintainable code within your application.

## sql`` template

One of the most common usages you may encounter in other ORMs as well 
is the ability to use `sql` queries as-is for raw queries.

```typescript copy
import { sql } from 'drizzle-orm' 

const id = 69;
await db.execute(sql`select * from ${usersTable} where ${usersTable.id} = ${id}`)
```

It will generate the current query

```sql
select * from "users" where "users"."id" = ?; --> [69]
```

Any tables and columns provided to the sql parameter are automatically mapped to their corresponding SQL 
syntax with escaped names for tables, and the escaped table names are appended to column names. 

Additionally, any dynamic parameters such as `${id}` will be mapped to the `?` placeholder, 
and the corresponding values will be moved to an array of values that are passed separately to the database. 

This approach effectively prevents any potential SQL Injection vulnerabilities.

## `sql<T>`

<Callout type="info" emoji="ℹ️">
    Please note that `sql<T>` does not perform any runtime mapping. The type you define using `sql<T>` is
    purely a helper for Drizzle. It is important to understand that there is no feasible way to 
    determine the exact type dynamically, as SQL queries can be highly versatile and customizable. 
</Callout>

You can define a custom type in Drizzle to be used in places where fields require a specific type other than `unknown`.

This feature is particularly useful in partial select queries, ensuring consistent typing for selected fields:

```typescript
// without sql<T> type defined
const response: { lowerName: unknown }[] = await db.select({
    lowerName: sql`lower(${usersTable.id})`
}).from(usersTable);

// with sql<T> type defined
const response: { lowerName: string }[] = await db.select({
    lowerName: sql<string>`lower(${usersTable.id})`
}).from(usersTable);
```

## `sql``.mapWith()`

For the cases you need to make a runtime mapping for values passed from database driver to drizzle you can use `.mapWith()`

This function accepts different values, that will map response in runtime.

You can replicate a specific column mapping strategy as long as
the interface inside mapWith is the same interface that is implemented by Column.

```typescript
import { sqliteTable, integer, text } from 'drizzle-orm/sqlite-core';

const usersTable = sqliteTable('users', {
    id: integer().primaryKey({ autoIncrement: true }),
    name: text().notNull(),
});

//  at runtime this values will be mapped same as `text` column is mapped in drizzle
sql`...`.mapWith(usersTable.name);
```

You can also pass your own implementation for the `DriverValueDecoder` interface:

```ts 
sql``.mapWith({
	mapFromDriverValue: (value: any) => {
		const mappedValue = value;
		// mapping you want to apply
		return mappedValue;
	},
});
    
// or
sql``.mapWith(Number);
```

## `sql``.as<T>()`

In different cases, it can sometimes be challenging to determine how to name a custom field that you want to use.
You may encounter situations where you need to explicitly specify an alias for a 
field that will be selected. This can be particularly useful when dealing with complex queries. 

To address these scenarios, we have introduced a helpful `.as('alias_name')` helper, which allows 
you to define an alias explicitly. By utilizing this feature, you can provide a clear and meaningful 
name for the field, making your queries more intuitive and readable.

<Section>
```typescript
sql`lower(usersTable.name)`.as('lower_name')
```
```sql
... (usersTable.name) as lower_name ...
```
</Section>

## `sql.raw()`

There are cases where you may not need to create parameterized values from input or map tables/columns to escaped ones. 
Instead, you might simply want to generate queries as they are. For such situations, we provide the `sql.raw()` function.

The `sql.raw()` function allows you to include raw SQL statements within your queries without any additional processing or escaping.
This can be useful when you have pre-constructed SQL statements or when you need to incorporate complex or dynamic 
SQL code directly into your queries.

<Section>
```typescript
sql.raw(`select * from users where id = ${12}`);
// vs
sql`select * from users where id = ${12}`;
```
```sql
select * from users where id = 12;
--> vs
select * from users where id = ?; --> [12]
```
</Section>

You can also utilize `sql.raw()` within the sql function, enabling you to include any raw string
without escaping it through the main `sql` template function.

By using `sql.raw()` inside the `sql` function, you can incorporate unescaped raw strings 
directly into your queries. This can be particularly useful when you have specific
SQL code or expressions that should remain untouched by the template function's automatic escaping or modification.

<Section>
```typescript
sql`select * from ${usersTable} where id = ${12}`;
// vs
sql`select * from ${usersTable} where id = ${sql.raw(12)}`;
```
```sql
select * from "users" where id = ?; --> [12]
--> vs
select * from "users" where id = 12;
```
</Section>

## sql.fromList()

The `sql` template generates sql chunks, which are arrays of SQL parts that will be concatenated 
into the query and params after applying the SQL to the database or query in Drizzle.

In certain scenarios, you may need to aggregate these chunks into an array using custom business 
logic and then concatenate them into a single SQL statement that can be passed to the database or query.
For such cases, the fromList function can be quite useful.

The fromList function allows you to combine multiple SQL chunks into a single SQL statement. 
You can use it to aggregate and concatenate the individual SQL parts according to your specific 
requirements and then obtain a unified SQL query that can be executed.

<Section>
```typescript
const sqlChunks: SQL[] = [];

sqlChunks.push(sql`select * from users`);

// some logic

sqlChunks.push(sql` where `);

// some logic

for (let i = 0; i < 5; i++) {
	sqlChunks.push(sql`id = ${i}`);

	if (i === 4) continue;
	sqlChunks.push(sql` or `);
}

const finalSql: SQL = sql.fromList(sqlChunks)
```
```sql
select * from users where id = ? or id = ? or id = ? or id = ? or id = ?; --> [0, 1, 2, 3, 4]
```
</Section>

## sql.join()

Indeed, the `sql.join` function serves a similar purpose to the fromList helper. 
However, it provides additional flexibility when it comes to handling spaces between
SQL chunks or specifying custom separators for concatenating the SQL chunks.

With `sql.join`, you can concatenate SQL chunks together using a specified separator. 
This separator can be any string or character that you want to insert between the chunks. 

This is particularly useful when you have specific requirements for formatting or delimiting 
the SQL chunks. By specifying a custom separator, you can achieve the desired structure and formatting 
in the final SQL query.

<Section>
```typescript
const sqlChunks: SQL[] = [];

sqlChunks.push(sql`select * from users`);

// some logic

sqlChunks.push(sql`where`);

// some logic

for (let i = 0; i < 5; i++) {
	sqlChunks.push(sql`id = ${i}`);

if (i === 4) continue;
    sqlChunks.push(sql`or`);
}

const finalSql: SQL = sql.join(sqlChunks, sql.raw(' '));
```
```sql
select * from users where id = ? or id = ? or id = ? or id = ? or id = ?; --> [0, 1, 2, 3, 4]
```
</Section>

## sql.append()

If you have already generated SQL using the `sql` template, you can achieve the same behavior as `fromList`
by using the append function to directly add a new chunk to the generated SQL.

By using the append function, you can dynamically add additional SQL chunks to the existing SQL string,
effectively concatenating them together. This allows you to incorporate custom logic or business 
rules for aggregating the chunks into the final SQL query.

<Section>
```typescript 
const finalSql = sql`select * from users`;

// some logic

finalSql.append(sql` where `);

// some logic

for (let i = 0; i < 5; i++) {
	finalSql.append(sql`id = ${i}`);

	if (i === 4) continue;
	finalSql.append(sql` or `);
}
```
```sql
select * from users where id = ? or id = ? or id = ? or id = ? or id = ?; --> [0, 1, 2, 3, 4]
```
</Section>

## sql.empty()

By using sql.empty(), you can start with a blank SQL object and then dynamically append SQL chunks to it as needed. This allows you to construct the SQL query incrementally, applying custom logic or conditions to determine the contents of each chunk.

Once you have initialized the SQL object using sql.empty(), you can take advantage of the full range
of sql template features such as parameterization, composition, and escaping. 
This empowers you to construct the SQL query in a flexible and controlled manner, 
adapting it to your specific requirements.

```typescript 
const finalSql = sql.empty();

// some logic

finalSql.append(sql`select * from users`);

// some logic

finalSql.append(sql` where `);

// some logic

for (let i = 0; i < 5; i++) {
	finalSql.append(sql`id = ${i}`);

	if (i === 4) continue;
	finalSql.append(sql` or `);
}
```
```sql
select * from users where id = ? or id = ? or id = ? or id = ? or id = ?; --> [0, 1, 2, 3, 4]
```

## Convert `sql` to string and params

In all the previous examples, you observed the usage of SQL template syntax in TypeScript along with 
the generated SQL output.

If you need to obtain the query string and corresponding parameters generated from the SQL template, 
you must specify the database dialect you intend to generate the query for. Different databases have
varying syntax for parameterization and escaping, so selecting the appropriate dialect is crucial.

Once you have chosen the dialect, you can utilize the corresponding implementation's functionality
to convert the SQL template into the desired query string and parameter format. This ensures 
compatibility with the specific database system you are working with.

<Section>
```typescript copy
import { SQLiteSyncDialect } from 'drizzle-orm/sqlite-core';

const sqliteDialect = new SQLiteSyncDialect();
sqliteDialect.sqlToQuery(sql`select * from ${usersTable} where ${usersTable.id} = ${12}`);
```
```sql
select * from "users" where "users"."id" = ?; --> [ 12 ]
```
</Section>

## `sql` select

You can use the sql functionality in partial select queries as well. Partial select queries allow you to 
retrieve specific fields or columns from a table rather than fetching the entire row.

For more detailed information about partial select queries, you can refer to the Core API
documentation available at **[Core API docs](/docs/sqlite/select#basic-and-partial-select)**.

**Select different custom fields from table**

Here you can see a usage for **[`sql<T>`](/docs/sqlite/sql#sqlt)**, **[`sql``.mapWith()`](/docs/sqlite/sql#sqlmapwith)**, **[`sql``.as<T>()`](/docs/sqlite/sql#sqlast)**.

<Section>
```typescript copy
import { sql } from 'drizzle-orm'
import { usersTable } from './schema'

await db.select({
    id: usersTable.id,
    lowerName: sql<string>`lower(${usersTable.name})`,
    aliasedName: sql<string>`lower(${usersTable.name})`.as('aliased_column'),
    count: sql<number>`count(*)`.mapWith(Number) 
}).from(usersTable)
```
```sql
select `id`, lower(`name`), lower(`name`) as `aliased_column`, count(*) from `users`;
```
</Section>

## `sql` in where

Indeed, Drizzle provides a set of available expressions that you can use within the sql template. 
However, it is true that databases often have a wider range of expressions available, 
including those provided through extensions or other means.

To ensure flexibility and enable you to utilize any expressions that are not natively
supported by Drizzle, you have the freedom to write the SQL template
directly using the sql function. This allows you to leverage the full power of
SQL and incorporate any expressions or functionalities specific to your target database.

By using the sql template, you are not restricted to only the predefined expressions in Drizzle. 
Instead, you can express complex queries and incorporate any supported expressions that 
the underlying database system provides.

**Filtering by `id` but with sql**
<Section>
```typescript copy
import { sql } from 'drizzle-orm'
import { usersTable } from './schema'

const id = 77

await db.select()
        .from(usersTable)
        .where(sql`${usersTable.id} = ${id}`)
```
```sql
select * from "users" where "users"."id" = ?; --> [ 77 ]
```
</Section>

**Advanced fulltext search where statement**
<Section>
```typescript copy
import { sql } from 'drizzle-orm'
import { usersTable } from './schema'

const searchPattern = "%Ale%"

await db.select()
        .from(usersTable)
        .where(sql`lower(${usersTable.name}) like lower(${searchPattern})`)
```
```sql
select * from "users" where lower("users"."name") like lower(?); --> [ "%Ale%" ]
```
</Section>

## `sql` in orderBy

The `sql` template can indeed be used in the ORDER BY clause when you need specific functionality for ordering that is not
available in Drizzle, but you prefer not to resort to raw SQL.

<Section>
```typescript copy
import { sql } from 'drizzle-orm'
import { usersTable } from './schema'

await db.select().from(usersTable).orderBy(sql`${usersTable.id} desc nulls first`)
```
```sql
select * from "users" order by "users"."id" desc nulls first;
```
</Section>

## `sql` in having and groupBy

The `sql` template can indeed be used in the HAVING and GROUP BY clauses when you need specific functionality for ordering that is not
available in Drizzle, but you prefer not to resort to raw SQL.

<Section>
```typescript copy
import { sql } from 'drizzle-orm'
import { usersTable } from './schema'

await db.select({ 
    projectId: usersTable.projectId,
    count: sql<number>`count(${usersTable.id})`.mapWith(Number)
}).from(usersTable)
    .groupBy(sql`${usersTable.projectId}`)
    .having(sql`count(${usersTable.id}) > 300`)
```
```sql
select "project_id", count("users"."id") from users group by "users"."project_id" having count("users"."id") > 300; 
```
</Section>


Source: https://orm.drizzle.team/docs/sqlite/transactions

# Transactions

SQL transaction is a grouping of one or more SQL statements that interact with a database.
A transaction in its entirety can commit to a database as a single logical unit
or rollback (become undone) as a single logical unit.

Drizzle ORM provides APIs to run SQL statements in transactions:

```ts copy
const db = drizzle(...)

await db.transaction(async (tx) => {
  await tx.update(accounts).set({ balance: sql`${accounts.balance} - 100.00` }).where(eq(users.name, 'Dan'));
  await tx.update(accounts).set({ balance: sql`${accounts.balance} + 100.00` }).where(eq(users.name, 'Andrew'));
});
```

Drizzle ORM supports `savepoints` with nested transactions API:

```ts copy {7-9}
const db = drizzle(...)

await db.transaction(async (tx) => {
  await tx.update(accounts).set({ balance: sql`${accounts.balance} - 100.00` }).where(eq(users.name, 'Dan'));
  await tx.update(accounts).set({ balance: sql`${accounts.balance} + 100.00` }).where(eq(users.name, 'Andrew'));

  await tx.transaction(async (tx2) => {
    await tx2.update(users).set({ name: "Mr. Dan" }).where(eq(users.name, "Dan"));
  });
});
```

You can embed business logic to the transaction and rollback whenever needed:

```ts copy {7}
const db = drizzle(...)

await db.transaction(async (tx) => {
  const [account] = await tx.select({ balance: accounts.balance }).from(accounts).where(eq(users.name, 'Dan'));
  if (account.balance < 100) {
    // This throws an exception that rollbacks the transaction.
    tx.rollback()
  }

  await tx.update(accounts).set({ balance: sql`${accounts.balance} - 100.00` }).where(eq(users.name, 'Dan'));
  await tx.update(accounts).set({ balance: sql`${accounts.balance} + 100.00` }).where(eq(users.name, 'Andrew'));
});
```

You can return values from the transaction:

```ts copy {8}
const db = drizzle(...)

const newBalance: number = await db.transaction(async (tx) => {
  await tx.update(accounts).set({ balance: sql`${accounts.balance} - 100.00` }).where(eq(users.name, 'Dan'));
  await tx.update(accounts).set({ balance: sql`${accounts.balance} + 100.00` }).where(eq(users.name, 'Andrew'));

  const [account] = await tx.select({ balance: accounts.balance }).from(accounts).where(eq(users.name, 'Dan'));
  return account.balance;
});
```

You can use transactions with **[relational queries](/docs/sqlite/rqb)**:

```ts
const db = drizzle({ schema })

await db.transaction(async (tx) => {
  await tx.query.users.findMany({
    with: {
      accounts: true
    }
  });
});
```

We provide dialect-specific transaction configuration APIs:

```ts {6}
await db.transaction(
  async (tx) => {
    await tx.update(accounts).set({ balance: sql`${accounts.balance} - 100.00` }).where(eq(users.name, "Dan"));
    await tx.update(accounts).set({ balance: sql`${accounts.balance} + 100.00` }).where(eq(users.name, "Andrew"));
  }, {
    behavior: "deferred",
  }
);

interface SQLiteTransactionConfig {
    behavior?: 'deferred' | 'immediate' | 'exclusive';
}
```


Source: https://orm.drizzle.team/docs/sqlite/typebox-legacy

import Npm from '@mdx/Npm.astro';
import Callout from '@mdx/Callout.astro';

# typebox-legacy

### Install the dependencies
<Npm>
drizzle-orm@rc @sinclair/typebox
</Npm>

### Select schema

Defines the shape of data queried from the database - can be used to validate API responses.

```ts copy
import { integer, sqliteTable, text } from 'drizzle-orm/sqlite-core';
import { createSelectSchema } from 'drizzle-orm/typebox-legacy';
import { Value } from '@sinclair/typebox/value';

const users = sqliteTable('users', {
  id: integer().primaryKey({ autoIncrement: true }),
  name: text().notNull(),
  age: integer().notNull()
});

const userSelectSchema = createSelectSchema(users);

const rows = await db.select({ id: users.id, name: users.name }).from(users).limit(1);
const parsed: { id: number; name: string; age: number } = Value.Parse(userSelectSchema, rows[0]); // Error: `age` is not returned in the above query

const rows = await db.select().from(users).limit(1);
const parsed: { id: number; name: string; age: number } = Value.Parse(userSelectSchema, rows[0]); // Will parse successfully
```

Views are also supported.

```ts copy
import { sqliteView } from 'drizzle-orm/sqlite-core';
import { gt } from 'drizzle-orm';
import { createSelectSchema } from 'drizzle-orm/typebox-legacy';
import { Value } from '@sinclair/typebox/value';

const usersView = sqliteView('users_view').as((qb) => qb.select().from(users).where(gt(users.age, 18)));
const usersViewSchema = createSelectSchema(usersView);
const parsed: { id: number; name: string; age: number } = Value.Parse(usersViewSchema, ...);
```

### Insert schema

Defines the shape of data to be inserted into the database - can be used to validate API requests.

```ts copy
import { integer, sqliteTable, text } from 'drizzle-orm/sqlite-core';
import { createInsertSchema } from 'drizzle-orm/typebox-legacy';
import { Value } from '@sinclair/typebox/value';

const users = sqliteTable('users', {
  id: integer().primaryKey({ autoIncrement: true }),
  name: text().notNull(),
  age: integer().notNull()
});

const userInsertSchema = createInsertSchema(users);

const user = { name: 'John' };
const parsed: { name: string, age: number } = Value.Parse(userInsertSchema, user); // Error: `age` is not defined

const user = { name: 'Jane', age: 30 };
const parsed: { name: string, age: number } = Value.Parse(userInsertSchema, user); // Will parse successfully
await db.insert(users).values(parsed);
```

### Update schema

Defines the shape of data to be updated in the database - can be used to validate API requests.

```ts copy
import { integer, sqliteTable, text } from 'drizzle-orm/sqlite-core';
import { createUpdateSchema } from 'drizzle-orm/typebox-legacy';
import { Value } from '@sinclair/typebox/value';

const users = sqliteTable('users', {
  id: integer().primaryKey({ autoIncrement: true }),
  name: text().notNull(),
  age: integer().notNull()
});

const userUpdateSchema = createUpdateSchema(users);

const user = { age: 35 };
const parsed: { name?: string | undefined, age?: number | undefined } = Value.Parse(userUpdateSchema, user); // Will parse successfully
await db.update(users).set(parsed).where(eq(users.name, 'Jane'));
```

### Refinements

Each create schema function accepts an additional optional parameter that you can used to extend, modify or completely overwite a field's schema. Defining a callback function will extend or modify while providing a Typebox schema will overwrite it.

```ts copy
import { integer, sqliteTable, text } from 'drizzle-orm/sqlite-core';
import { createSelectSchema } from 'drizzle-orm/typebox-legacy';
import { Type } from '@sinclair/typebox';
import { Value } from '@sinclair/typebox/value';

const users = sqliteTable('users', {
  id: integer().primaryKey({ autoIncrement: true }),
  name: text().notNull(),
  bio: text(),
  preferences: text({ mode: 'json' })
});

const userSelectSchema = createSelectSchema(users, {
  name: (schema) => Type.String({ ...schema, maxLength: 20 }), // Extends schema
  bio: (schema) => Type.String({ ...schema, maxLength: 1000 }), // Extends schema before becoming nullable/optional
  preferences: Type.Object({ theme: Type.String() }) // Overwrites the field, including its nullability
});

const parsed: {
  id: number;
  name: string,
  bio: string | null;
  preferences: {
    theme: string;
  };
} = Value.Parse(userSelectSchema, ...);
```

### Factory functions

For more advanced use cases, you can use the `createSchemaFactory` function.

**Use case: Using an extended Typebox instance**

```ts copy
import { integer, sqliteTable, text } from 'drizzle-orm/sqlite-core';
import { createSchemaFactory } from 'drizzle-orm/typebox';
import { t } from 'elysia'; // Extended Typebox instance

const users = sqliteTable('users', {
  id: integer().primaryKey({ autoIncrement: true }),
  name: text().notNull(),
  age: integer().notNull()
});

const { createInsertSchema } = createSchemaFactory({ typeboxInstance: t });

const userInsertSchema = createInsertSchema(users, {
  // We can now use the extended instance
  name: (schema) => t.Number({ ...schema }, { error: '`name` must be a string' })
});
```

### Data type reference

```ts
sqlite.integer({ mode: 'boolean' });

// Schema
Type.Boolean();
```

```ts
sqlite.integer({ mode: 'timestamp' });
sqlite.integer({ mode: 'timestamp_ms' });

// Schema
Type.Date();
```

```ts
sqlite.numeric();
sqlite.text({ mode: 'text' });

// Schema
Type.String();
```

```ts
sqlite.numeric({ mode: 'number' });

// Schema
Type.Number({ minimum: -9_007_199_254_740_991, maximum: 9_007_199_254_740_991 }); // Javascript min. and max. safe integers
```

```ts
sqlite.numeric({ mode: 'bigint' });

// Schema
Type.BigInt({ minimum: -9_223_372_036_854_775_808n, maximum: 9_223_372_036_854_775_807n }); // 64-bit integer lower and upper limit
```

```ts
sqlite.text({ mode: 'text', length: ... });

// Schema
Type.String({ maxLength: length });
```

```ts
sqlite.text({ mode: 'text', enum: ... });

// Schema
Type.Enum(enum);
```

```ts
sqlite.real();

// Schema
Type.Number({ minimum: -140_737_488_355_328, maximum: 140_737_488_355_327 }); // 48-bit integer lower and upper limit
```

```ts
sqlite.integer({ mode: 'number' });

// Schema
Type.Integer({ minimum: -9_007_199_254_740_991, maximum: 9_007_199_254_740_991 }); // Javascript min. and max. safe integers
```

```ts
sqlite.blob({ mode: 'bigint' });

// Schema
Type.BigInt({ minimum: -9_223_372_036_854_775_808n, maximum: 9_223_372_036_854_775_807n }); // 64-bit integer lower and upper limit
```

```ts
sqlite.blob({ mode: 'json' });
sqlite.text({ mode: 'json' });

// Schema
Type.Recursive((self) => Type.Union([Type.Union([Type.String(), Type.Number(), Type.Boolean(), Type.Null()]), Type.Array(self), Type.Record(Type.String(), self)]));
```

```ts
sqlite.blob({ mode: 'buffer' });

// Schema
t.Union([t.Union([t.String(), t.Number(), t.Boolean(), t.Null()]), t.Array(t.Any()), t.Record(t.String(), t.Any())]);
```


Source: https://orm.drizzle.team/docs/sqlite/typebox

import Npm from '@mdx/Npm.astro';
import Callout from '@mdx/Callout.astro';

# typebox

#### Install the dependencies
<Npm>
drizzle-orm@rc typebox
</Npm>

Allows you to generate [typebox](https://sinclairzx81.github.io/typebox/#/) schemas from Drizzle ORM schemas

**Features**

- Create a select schema for tables and views.
- Create insert and update schemas for tables.
- Supported dialect: SQLite.

#### Usage

```ts
import { integer, sqliteTable, text } from 'drizzle-orm/sqlite-core';
import { createInsertSchema, createSelectSchema, createUpdateSchema } from 'drizzle-orm/typebox';
import { Type } from 'typebox';
import { Value } from 'typebox/value';

const users = sqliteTable('users', {
	id: integer().primaryKey({ autoIncrement: true }),
	name: text().notNull(),
	email: text().notNull(),
	role: text({ enum: ['admin', 'user'] }).notNull(),
	createdAt: integer('created_at', { mode: 'timestamp' }).notNull(),
});

// Schema for inserting a user - can be used to validate API requests
const insertUserSchema = createInsertSchema(users);

// Schema for updating a user - can be used to validate API requests
const updateUserSchema = createUpdateSchema(users);

// Schema for selecting a user - can be used to validate API responses
const selectUserSchema = createSelectSchema(users);

// Overriding the fields
const insertUserSchema = createInsertSchema(users, {
	role: Type.String(),
});

// Refining the fields - useful if you want to change the fields before they become nullable/optional in the final schema
const insertUserSchema = createInsertSchema(users, {
	id: (schema) => Type.Number({ ...schema, minimum: 0 }),
	role: Type.String(),
});

// Usage

const isUserValid: boolean = Value.Check(insertUserSchema, {
	name: 'John Doe',
	email: 'johndoe@test.com',
	role: 'admin',
});
```


Source: https://orm.drizzle.team/docs/sqlite/update

import Callout from '@mdx/Callout.astro';
import Section from '@mdx/Section.astro';

# SQL Update

<Callout type='info'>
All the values provided to `.set()`are parameterized automatically.
For example, this query:
```ts
await db.update(users).set({ name: "Mr. Dan" }).where(eq(users.name, "Dan"));
```
will be translated to:
```sql
update "users" set "name" = ? where "users"."name" = ?; -- params: ['Mr. Dan', 'Dan']
```
</Callout>

<br/>

The object that you pass to `update` should have keys that match column names in your database schema.
Values of `undefined` are ignored in the object: to set a column to `null`, pass `null`.

```typescript copy
await db.update(users)
  .set({ name: 'Mr. Dan' })
  .where(eq(users.name, 'Dan'));
```
```typescript copy
await db.update(users)
  .set({ name: null })
  .where(eq(users.name, 'Dan'));
```

You can pass SQL as a value to be used in the update object, like this:

```typescript copy
await db.update(users)
  .set({ updatedAt: sql`NOW()` })
  .where(eq(users.name, 'Dan'));
```

### Limit
Use `.limit()` to add `limit` clause to the query - for example:
<Section>
```typescript
await db.update(usersTable).set({ verified: true }).limit(2);
```
```sql
update "users" set "verified" = ? limit ?;
```
</Section>

### Order By
Use `.orderBy()` to add `order by` clause to the query, sorting the results by the specified fields:
<Section>
```typescript
import { asc, desc } from 'drizzle-orm';

await db.update(usersTable).set({ verified: true }).orderBy(usersTable.name);
await db.update(usersTable).set({ verified: true }).orderBy(desc(usersTable.name));

// order by multiple fields
await db.update(usersTable).set({ verified: true }).orderBy(usersTable.name, usersTable.name2);
await db.update(usersTable).set({ verified: true }).orderBy(asc(usersTable.name), desc(usersTable.name2));
```
```sql
update "users" set "verified" = ? order by "name";
update "users" set "verified" = ? order by "name" desc;

update "users" set "verified" = ? order by "name", "name2";
update "users" set "verified" = ? order by "name" asc, "name2" desc;
```
</Section>

### Returning
You can update a row and get it back in SQLite:
```typescript copy
const updatedUserId = await db.update(users).set({ name: "Mr. Dan" }).where(eq(users.name, "Dan")).returning({ updatedId: users.id });
//      ^ { updatedId: number | null }[]
```
```sql
update "users" set "name" = 'Mr. Dan' where "users"."name" = 'Dan' returning "id";
```

## `with update` clause

<Callout>
  Check how to use WITH statement with [select](/docs/sqlite/select#with-clause), [insert](/docs/sqlite/insert#with-insert-clause), [delete](/docs/sqlite/delete#with-delete-clause)
</Callout>

Using the `with` clause can help you simplify complex queries by splitting them into smaller subqueries called common table expressions (CTEs):
<Section>
```typescript copy
const averagePrice = db.$with('average_price').as(
	db.select({ value: sql`avg(${products.price})`.as('value') }).from(products)
);

const result = await db.with(averagePrice)
	.update(products)
	.set({
		cheap: true
	})
	.where(lt(products.price, sql`(select * from ${averagePrice})`))
	.returning({
		id: products.id
	});
```
```sql
with "average_price" as (select avg("price") as "value" from "products") 
update "products" set "cheap" = true 
where "products"."price" < (select * from "average_price") 
returning "id"
```
</Section>

## Update ... from
As the SQLite documentation mentions:

> 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

<Section>
```ts
await db
  .update(users)
  .set({ cityId: cities.id })
  .from(cities)
  .where(and(eq(cities.name, 'Seattle'), eq(users.name, 'John')))
```
```sql
update "users" set "city_id" = "cities"."id" 
from "cities" 
where (("cities"."name" = 'Seattle') and ("users"."name" = 'John'))
```
</Section>

You can also alias tables that are joined (you can also alias the updating table too).
<Section>
```ts
const c = alias(cities, 'c');
await db
  .update(users)
  .set({ cityId: c.id })
  .from(c);
```
```sql
update "users" set "city_id" = "c"."id" 
from "cities" "c"
```
</Section>

In SQLite, you can also return columns from the joined tables.
<Section>
```ts
const updatedUsers = await db
  .update(users)
  .set({ cityId: cities.id })
  .from(cities)
  .returning({ id: users.id, cityName: cities.name });
```
```sql
update "users" set "city_id" = "cities"."id" 
from "cities" 
returning "users"."id", "cities"."name"
```
</Section>


Source: https://orm.drizzle.team/docs/sqlite/upgrade-v1

import Npm from "@mdx/Npm.astro";
import Npx from "@mdx/Npx.astro";
import Prerequisites from "@mdx/Prerequisites.astro";

# Upgrading to Drizzle v1

<Npm>
 drizzle-orm@rc
 -D drizzle-kit@rc
</Npm>

#### Step 1 - Run `drizzle-kit up`

> v3 migration folder discussion: https://github.com/drizzle-team/drizzle-orm/discussions/2832  

We've updated the migrations folder structure by:
- removing `journal.json`
- grouping SQL files and snapshots into separate migration folders
- removing the `drizzle-kit drop` command

These changes eliminate potential Git conflicts with the journal file and simplify the process of dropping or fixing conflicted migrations

The drizzle-kit has been architecturally redesigned:
- Migrated from database snapshots to DDL snapshots

Commutativity checks were added:
- Detecting non-commutative migrations across branches
> Commutativity discussion: https://github.com/drizzle-team/drizzle-orm/discussions/5005

To migrate from old structure to a new one you would need to run

<Npx>
drizzle-kit up
</Npx>

#### Step 2 - Review breaking changes

You can find out the full list of breaking changes [here](/docs/sqlite/v0-v1-changes#breaking-changes) and make sure to update your code accordingly

If you were using Relational Queries, you need to upgrade to v2:
- [How to migrate relations definition from v1 to v2](/docs/sqlite/relations-v1-v2#how-to-migrate-relations-schema-definition-from-v1-to-v2)
- [How to migrate queries from v1 to v2](/docs/sqlite/relations-v1-v2#how-to-migrate-queries-from-v1-to-v2)

#### Step 3 - Done ✅


Source: https://orm.drizzle.team/docs/sqlite/v0-v1-changes

import Callout from '@mdx/Callout.astro';

# Changes in v1

This page shows everything that changed from `drizzle-orm@0.x`, `drizzle-kit@0.x`, `drizzle-seed@0.x` to the latest `drizzle-orm@1.0`, `drizzle-kit@1.0`, `drizzle-seed@1.0`

<Callout type="info">
Read more on how to upgrade [here](/docs/sqlite/upgrade-v1)
</Callout>

## Breaking changes

#### Foreign key handling in pre-v1.0
The old `drizzle-kit` didn't pass FK names from TS schema through to generated SQL:
```ts {6}
export const table = sqliteTable("table", {
  column1: integer(),
  column2: integer(),
}, (t) => [
  foreignKey({
    name: "name",
    columns: [t.column1],
    foreignColumns: [t.column2],
  }),
]);
```
```sql {5}
-- Before: no name in generated SQL
CREATE TABLE `table` (
	`column1` integer,
	`column2` integer,
	FOREIGN KEY (`column1`) REFERENCES `table`(`column2`) ON UPDATE no action ON DELETE no action
);
```

On `introspect`, drizzle-kit parses DDL to find the constraint name; if none is found, the default name is used.

After upgrading to v1, the first `push` will produce a diff that recreates the table (DB has no name, TS does). **To avoid this, remove the FK name from the TS schema** - no diff will be generated.

`drizzle-kit generate` behaves as expected; no changes needed.

#### Relational Queries v1 removed

RQBv1 has been removed. Use [Relational Queries v2](/docs/sqlite/relations) with the new `defineRelations()` API instead and new features. You can find more details about migrating from rqb v1 to v2 [here](/docs/sqlite/relations-v1-v2)

A new relations system built around `defineRelations()`:

```ts
import { defineRelations } from 'drizzle-orm';

const relations = defineRelations(schema, (r) => ({
  users: {
    posts: r.many.posts(),
    profile: r.one.profiles(),
  },
  posts: {
    author: r.one.users({
      from: posts.authorId,
      to: users.id,
    }),
  },
}));
```

#### New Casing API

The legacy `drizzle({ casing: 'camelCase' })` has been replaced with a table/view/schema-level API:

```ts
import { snakeCase, camelCase } from 'drizzle-orm/pg-core';

export const users = snakeCase.table('users', {
  id: serial().primaryKey(),
  fullName: text(),        // → full_name in DB
  createdAt: timestamp(),  // → created_at in DB
});

// Available on all entity types:
snakeCase.table / snakeCase.view / snakeCase.materializedView / snakeCase.schema
camelCase.table / camelCase.view / camelCase.materializedView / camelCase.schema
```

#### Validator packages consolidated into `drizzle-orm`

<Callout type="warning">
You can still use drizzle-zod/valibot/typebox/arktype validation packages but all new update will be added to Drizzle ORM directly
</Callout>

- drizzle-zod -> drizzle-orm/zod
- drizzle-valibot -> drizzle-orm/valibot
- drizzle-typebox -> drizzle-orm/typebox-legacy (using @sinclair/typebox)
- drizzle-typebox -> drizzle-orm/typebox (using typebox)
- drizzle-arktype -> drizzle-orm/arktype
- new `drizzle-orm/effect-schema` package added

#### `.generatedAlwaysAs()` only accepts SQL

```ts
// ❌ Before — accepted raw values
.generatedAlwaysAs('some expression')

// ✅ After — only sql`` or () => sql``
.generatedAlwaysAs(sql`some expression`)
.generatedAlwaysAs(() => sql`some expression`)
```

#### `getTableColumns` deprecation

Use `getColumns` instead

```ts
// ❌ Before
import { getTableColumns } from 'drizzle-orm';

const columns = getTableColumns(users);

// ✅ After
import { getColumns } from 'drizzle-orm';

const columns = getColumns(users);
```

#### New migration folder structure (v3)

**Linked discussion**: [#2832](https://github.com/drizzle-team/drizzle-orm/discussions/2832)

<br/>

- No more `journal.json`
- SQL files and snapshots grouped into separate migration folders
- `drizzle-kit drop` command removed

These changes eliminate potential Git conflicts with the journal file and simplify the process of dropping or fixing conflicted migrations

<Callout type="info">
Read more on how to upgrade [here](/docs/sqlite/upgrade-v1)
</Callout>

#### `drizzle-kit push --strict` deprecation

The `--strict` flag has been removed — its behavior is now the default. `drizzle-kit push` always prompts for confirmation for data-loss statements unless the `--force` flag is passed. Use [drizzle-kit push --explain](/docs/sqlite/drizzle-kit-push) to preview the SQL that would be executed before running it.

#### Drizzle seed: UUID generator upgraded to v4

The UUID generator now produces RFC 4122 v4 compliant UUIDs, ensuring compatibility with Zod v4 validation. Use `{ version: '1' }` to keep old behavior, or `{ version: '2' | '3' }` for newer generators.

## Other features

#### JIT Mappers (opt-in)

Just-in-time compiled row mappers that make mapping as fast as the raw driver.
You can find out more [here](/docs/sqlite/jit-mappers)

```ts {1}
const db = drizzle({ ..., jit: true });
```

#### New MSSQL dialect

New MSSQL dialect support added. You can read more [here](/docs/mssql/get-started-mssql)

#### New CockroachDB dialect

New CockroachDB dialect support added. You can read more [here](/docs/cockroach/get-started-cockroach)

#### Column aliases via `.as()`

You can find out more aliasing info [here](/docs/sqlite/aliases)
```ts
const query = db
  .select({ age: users.age.as('ageOfUser'), id: users.id.as('userId') })
  .from(users)
  .orderBy(asc(users.id.as('userId')));
```

#### `drizzle-kit pull --init`

Creates the drizzle migration table and marks the first pulled migration as applied. You can read more [here](/docs/sqlite/drizzle-kit-pull)

#### `drizzle-kit push --explain`

Shows the SQL that would be executed without actually running it. You can read more [here](/docs/sqlite/drizzle-kit-push)

#### `drizzle-kit check` — commutativity check

Detects non-commutative migrations across branches — e.g., two branches altering the same column, or one renaming a table that another is altering.

How it works:
- Builds a DAG from snapshot `prevIds` to understand branch structure
- Finds fork points where branches diverged
- Computes the DDL diff from parent snapshot to each branch leaf
- Checks conflicts using a footprint map of which DDL statement types can interfere

If conflicts are found, the report tells you exactly which migrations on which branches are incompatible and which statements collide.

#### `drizzle-kit --ignore-conflicts` flag

Bypasses commutativity checks when you know the conflicts are expected.

#### `drizzle-kit generate`: migration conflict detection

`drizzle-kit generate` now identifies [incompatible changes](/docs/sqlite/v0-v1-changes#drizzle-kit-check--commutativity-check) across migration branches. Use `--ignore-conflicts` to bypass.

#### Updates to the migration table

The migration table is automatically upgraded when you run `drizzle-kit up`. Two new columns are added:

- **`name`** — the full migration folder name (e.g. `20250220153045_brave_wolverine`)
- **`applied_at`** — timestamp of when the migration was executed (pre-existing rows are backfilled with `NULL`)

| Column | Type | v0 | v1 |
| --- | --- | --- |:---:|
| `id` | integer | yes | yes |
| `hash` | text | yes | yes |
| `created_at` | numeric | yes | yes (legacy) |
| `name` | text | — | new |
| `applied_at` | text | — | new |

Migrations are now matched by their full folder name instead of timestamps. Even if two migrations are generated within the same second, the name suffix guarantees uniqueness.

During the upgrade, existing rows are backfilled using a multi-step strategy:
1. **Millis match** — truncate stored millis to seconds, match against local folder timestamps
2. **Hash tiebreaker** — if multiple migrations share the same second, disambiguate via the SQL hash
3. **Hash-only fallback** — if millis matching fails entirely, match by hash alone

<br/>
This means the upgrade handles all edge cases: normal single-developer projects, teams with closely-timed migrations, and even cases where the old journal data doesn't perfectly align with the new folder names.

#### Migrator applies all missing migrations

Previously the migrator only looked for local migrations with a creation date later than the last applied one. Now it detects and applies **every missing migration**, regardless of timestamp ordering. All migrations are matched against the full folder name (14-digit UTC timestamp + name suffix).

#### Top-level `await` in drizzle config files

Top-level `await` is now supported in `drizzle.config.ts` and schema files on Node.js.

#### Drizzle-kit: Build system improvements

- Migrated from `esbuild-register` to `tsx` loader — seamless ESM and CJS support
- Native Bun and Deno launch support

#### TS Schema file processing

Only files with the following extensions are processed: `.js`, `.mjs`, `.cjs`, `.jsx`, `.ts`, `.mts`, `.cts`, `.tsx`. All other file types are ignored.

#### Drizzle Seed: Ignore columns in refinements

Skip specific columns during seeding — the database default will be used instead:

```ts
await seed(db, schema).refine((f) => ({
  users: {
    count: 5,
    columns: {
      name: f.fullName(),
      photo: false, // skip — DB default will be used
    },
  },
}));
```

#### `min` / `max` parameters

Time-based generators now accept boundaries:

```ts
funcs.time({ min: '13:12:13', max: '15:12:13' })
funcs.timestamp({ min: '2024-01-01T00:00:00Z', max: '2025-01-01T00:00:00Z' })
funcs.datetime({ min: '2024-01-01', max: '2025-01-01' })
```

Source: https://orm.drizzle.team/docs/sqlite/valibot

import Npm from '@mdx/Npm.astro';
import Callout from '@mdx/Callout.astro';

# valibot

### Install the dependencies

<Npm>
drizzle-orm@rc valibot
</Npm>

### Select schema

Defines the shape of data queried from the database - can be used to validate API responses.

```ts copy
import { integer, sqliteTable, text } from 'drizzle-orm/sqlite-core';
import { createSelectSchema } from 'drizzle-orm/valibot';
import { parse } from 'valibot';

const users = sqliteTable('users', {
  id: integer().primaryKey({ autoIncrement: true }),
  name: text().notNull(),
  age: integer().notNull()
});

const userSelectSchema = createSelectSchema(users);

const rows = await db.select({ id: users.id, name: users.name }).from(users).limit(1);
const parsed: { id: number; name: string; age: number } = parse(userSelectSchema, rows[0]); // Error: `age` is not returned in the above query

const rows = await db.select().from(users).limit(1);
const parsed: { id: number; name: string; age: number } = parse(userSelectSchema, rows[0]); // Will parse successfully
```

Views are also supported.

```ts copy
import { sqliteView } from 'drizzle-orm/sqlite-core';
import { gt } from 'drizzle-orm';
import { createSelectSchema } from 'drizzle-orm/valibot';
import { parse } from 'valibot';

const usersView = sqliteView('users_view').as((qb) => qb.select().from(users).where(gt(users.age, 18)));
const usersViewSchema = createSelectSchema(usersView);
const parsed: { id: number; name: string; age: number } = parse(usersViewSchema, ...);
```

### Insert schema

Defines the shape of data to be inserted into the database - can be used to validate API requests.

```ts copy
import { integer, sqliteTable, text } from 'drizzle-orm/sqlite-core';
import { createInsertSchema } from 'drizzle-orm/valibot';
import { parse } from 'valibot';

const users = sqliteTable('users', {
  id: integer().primaryKey({ autoIncrement: true }),
  name: text().notNull(),
  age: integer().notNull()
});

const userInsertSchema = createInsertSchema(users);

const user = { name: 'John' };
const parsed: { name: string, age: number } = parse(userInsertSchema, user); // Error: `age` is not defined

const user = { name: 'Jane', age: 30 };
const parsed: { name: string, age: number } = parse(userInsertSchema, user); // Will parse successfully
await db.insert(users).values(parsed);
```

### Update schema

Defines the shape of data to be updated in the database - can be used to validate API requests.

```ts copy
import { integer, sqliteTable, text } from 'drizzle-orm/sqlite-core';
import { createUpdateSchema } from 'drizzle-orm/valibot';
import { parse } from 'valibot';

const users = sqliteTable('users', {
  id: integer().primaryKey({ autoIncrement: true }),
  name: text().notNull(),
  age: integer().notNull()
});

const userUpdateSchema = createUpdateSchema(users);

const user = { age: 35 };
const parsed: { name?: string | undefined, age?: number | undefined } = parse(userUpdateSchema, user); // Will parse successfully
await db.update(users).set(parsed).where(eq(users.name, 'Jane'));
```

### Refinements

Each create schema function accepts an additional optional parameter that you can used to extend, modify or completely overwite a field's schema. Defining a callback function will extend or modify while providing a Valibot schema will overwrite it.

```ts copy
import { integer, sqliteTable, text } from 'drizzle-orm/sqlite-core';
import { createSelectSchema } from 'drizzle-orm/valibot';
import { parse, pipe, maxLength, object, string } from 'valibot';

const users = sqliteTable('users', {
  id: integer().primaryKey({ autoIncrement: true }),
  name: text().notNull(),
  bio: text(),
  preferences: text({ mode: 'json' })
});

const userSelectSchema = createSelectSchema(users, {
  name: (schema) => pipe(schema, maxLength(20)), // Extends schema
  bio: (schema) => pipe(schema, maxLength(1000)), // Extends schema before becoming nullable/optional
  preferences: object({ theme: string() }) // Overwrites the field, including its nullability
});

const parsed: {
  id: number;
  name: string,
  bio: string | null;
  preferences: {
    theme: string;
  };
} = parse(userSelectSchema, ...);
```

### Data type reference

```ts
sqlite.integer({ mode: 'boolean' });

// Schema
boolean();
```

```ts
sqlite.integer({ mode: 'timestamp' });
sqlite.integer({ mode: 'timestamp_ms' });

// Schema
date();
```

```ts
sqlite.numeric();
sqlite.text({ mode: 'text' });

// Schema
string();
```

```ts
sqlite.numeric({ mode: 'number' });

// Schema
pipe(number(), minValue(-9_007_199_254_740_991), maxValue(9_007_199_254_740_991)); // Javascript min. and max. safe integers
```

```ts
sqlite.numeric({ mode: 'bigint' });

// Schema
pipe(bigint(), minValue(-9_223_372_036_854_775_808n), maxValue(9_223_372_036_854_775_807n)); // 64-bit integer lower and upper limit
```

```ts
sqlite.text({ mode: 'text', length: ... });

// Schema
pipe(string(), maxLength(length));
```

```ts
sqlite.text({ mode: 'text', enum: ... });

// Schema
enum(enum);
```

```ts
sqlite.real();

// Schema
pipe(number(), minValue(-140_737_488_355_328), maxValue(140_737_488_355_327)); // 48-bit integer lower and upper limit
```

```ts
sqlite.integer({ mode: 'number' });

// Schema
pipe(number(), minValue(-9_007_199_254_740_991), maxValue(9_007_199_254_740_991), integer()); // Javascript min. and max. safe integers
```

```ts
sqlite.blob({ mode: 'bigint' });

// Schema
pipe(bigint(), minValue(-9_223_372_036_854_775_808n), maxValue(9_223_372_036_854_775_807n)); // 64-bit integer lower and upper limit
```

```ts
sqlite.blob({ mode: 'json' });
sqlite.text({ mode: 'json' });

// Schema
union([union([string(), number(), boolean(), null_()]), array(any()), record(string(), any())]);
```

```ts
sqlite.blob({ mode: 'buffer' });

// Schema
custom<Buffer>((v) => v instanceof Buffer);
```


Source: https://orm.drizzle.team/docs/sqlite/views

import Callout from '@mdx/Callout.astro';
import Section from '@mdx/Section.astro';

# Views

There're several ways you can declare views with Drizzle ORM.  

You can declare views that have to be created or you can declare views that already exist in the database. 

You can declare views statements with an inline `query builder` syntax, with `standalone query builder` and with raw `sql` operators. 

When views are created with either inlined or standalone query builders, view columns schema will be automatically inferred, 
yet when you use `sql` you have to explicitly declare view columns schema.

### Declaring views

<Section>
      ```ts filename="schema.ts" copy {13-14}
      import { integer, text, sqliteView, sqliteTable } from "drizzle-orm/sqlite-core";
      import { eq } from 'drizzle-orm';

      export const user = sqliteTable("user", {
        id: integer().primaryKey({ autoIncrement: true }),
        name: text(),
        email: text(),
        password: text(),
        role: text().$type<"admin" | "customer">(),
        createdAt: integer("created_at"),
        updatedAt: integer("updated_at"),
      });

      export const userView = sqliteView("user_view").as((qb) => qb.select().from(user));
      export const customersView = sqliteView("customers_view").as((qb) => qb.select().from(user).where(eq(user.role, "customer")));
      ```
      ```sql
      CREATE VIEW `user_view` AS select "id", ... from "user";
      CREATE VIEW `customers_view` AS select "id", ... from "user" where "user"."role" = 'customer';
      ```
    </Section>

You can also declare views using `standalone query builder`, it works exactly the same way:

<Section>
      ```ts filename="schema.ts" copy {3, 15-16}
      import { integer, text, sqliteView, sqliteTable, QueryBuilder } from "drizzle-orm/sqlite-core";
      import { eq } from 'drizzle-orm';

      const qb = new QueryBuilder();

      export const user = sqliteTable("user", {
        id: integer().primaryKey({ autoIncrement: true }),
        name: text(),
        email: text(),
        password: text(),
        role: text().$type<"admin" | "customer">(),
        createdAt: integer("created_at"),
        updatedAt: integer("updated_at"),
      });

      export const userView = sqliteView("user_view").as(() => qb.select().from(user));
      export const customerView = sqliteView("customers_view").as((qb) => qb.select().from(user).where(eq(user.role, "customer")));
      ```
      ```sql
      CREATE VIEW `user_view` AS select "id", ... from "user";
      CREATE VIEW `customers_view` AS select "id", ... from "user" where "user"."role" = 'customer';
      ```
    </Section>

### Declaring views with raw SQL
Whenever you need to declare view using a syntax that is not supported by the query builder, 
you can directly use `sql` operator and explicitly specify view columns schema.

```ts copy
// regular view
const newYorkers = sqliteView('new_yorkers', {
  id: integer('id').primaryKey({ autoIncrement: true }),
  name: text('name').notNull(),
  cityId: integer('city_id').notNull(),
}).as(sql`select * from ${users} where ${eq(users.cityId, 1)}`);
```

### Declaring existing views
When you're provided with a read only access to an existing view in the database you should use `.existing()` view configuration, 
`drizzle-kit` will ignore and will not generate a `create view` statement in the generated migration.
```ts
export const user = sqliteTable("user", {
  id: integer().primaryKey({ autoIncrement: true }),
  name: text(),
  email: text(),
  password: text(),
  role: text().$type<"admin" | "customer">(),
  createdAt: timestamp("created_at"),
  updatedAt: timestamp("updated_at"),
});

// regular view
export const trimmedUser = sqliteView("trimmed_user", {
  id: integer("id"),
  name: text("name"),
  email: text("email"),
}).existing();
```


Source: https://orm.drizzle.team/docs/sqlite/zod

import Npm from '@mdx/Npm.astro';
import Callout from '@mdx/Callout.astro';

# zod

### Install the dependencies

<Npm>
drizzle-orm@rc zod
</Npm>

### Select schema

Defines the shape of data queried from the database - can be used to validate API responses.

```ts copy
import { integer, sqliteTable, text } from 'drizzle-orm/sqlite-core';
import { createSelectSchema } from 'drizzle-orm/zod';

const users = sqliteTable('users', {
  id: integer().primaryKey({ autoIncrement: true }),
  name: text().notNull(),
  age: integer().notNull()
});

const userSelectSchema = createSelectSchema(users);

const rows = await db.select({ id: users.id, name: users.name }).from(users).limit(1);
const parsed: { id: number; name: string; age: number } = userSelectSchema.parse(rows[0]); // Error: `age` is not returned in the above query

const rows = await db.select().from(users).limit(1);
const parsed: { id: number; name: string; age: number } = userSelectSchema.parse(rows[0]); // Will parse successfully
```

Views are also supported.

```ts copy
import { sqliteView } from 'drizzle-orm/sqlite-core';
import { gt } from 'drizzle-orm';
import { createSelectSchema } from 'drizzle-orm/zod';

const usersView = sqliteView('users_view').as((qb) => qb.select().from(users).where(gt(users.age, 18)));
const usersViewSchema = createSelectSchema(usersView);
const parsed: { id: number; name: string; age: number } = usersViewSchema.parse(...);
```

### Insert schema

Defines the shape of data to be inserted into the database - can be used to validate API requests.

```ts copy
import { integer, sqliteTable, text } from 'drizzle-orm/sqlite-core';
import { createInsertSchema } from 'drizzle-orm/zod';

const users = sqliteTable('users', {
  id: integer().primaryKey({ autoIncrement: true }),
  name: text().notNull(),
  age: integer().notNull()
});

const userInsertSchema = createInsertSchema(users);

const user = { name: 'John' };
const parsed: { name: string, age: number } = userInsertSchema.parse(user); // Error: `age` is not defined

const user = { name: 'Jane', age: 30 };
const parsed: { name: string, age: number } = userInsertSchema.parse(user); // Will parse successfully
await db.insert(users).values(parsed);
```

### Update schema

Defines the shape of data to be updated in the database - can be used to validate API requests.

```ts copy
import { integer, sqliteTable, text } from 'drizzle-orm/sqlite-core';
import { createUpdateSchema } from 'drizzle-orm/zod';

const users = sqliteTable('users', {
  id: integer().primaryKey({ autoIncrement: true }),
  name: text().notNull(),
  age: integer().notNull()
});

const userUpdateSchema = createUpdateSchema(users);

const user = { age: 35 };
const parsed: { name?: string | undefined, age?: number | undefined } = userUpdateSchema.parse(user); // Will parse successfully
await db.update(users).set(parsed).where(eq(users.name, 'Jane'));
```

### Refinements

Each create schema function accepts an additional optional parameter that you can used to extend, modify or completely overwite a field's schema. Defining a callback function will extend or modify while providing a Zod schema will overwrite it.

```ts copy
import { integer, sqliteTable, text } from 'drizzle-orm/sqlite-core';
import { createSelectSchema } from 'drizzle-orm/zod';
import { z } from 'zod/v4';

const users = sqliteTable('users', {
  id: integer().primaryKey(),
  name: text().notNull(),
  bio: text(),
  preferences: text({ mode: 'json' })
});

const userSelectSchema = createSelectSchema(users, {
  name: (schema) => schema.max(20), // Extends schema
  bio: (schema) => schema.max(1000), // Extends schema before becoming nullable/optional
  preferences: z.object({ theme: z.string() }) // Overwrites the field, including its nullability
});

const parsed: {
  id: number;
  name: string,
  bio: string | null;
  preferences: {
    theme: string;
  };
} = userSelectSchema.parse(...);
```

### Factory functions

For more advanced use cases, you can use the `createSchemaFactory` function.

**Use case: Using an extended Zod instance**

```ts copy
import { integer, sqliteTable, text } from 'drizzle-orm/sqlite-core';
import { createSchemaFactory } from 'drizzle-orm/zod';
import { z } from '@hono/zod-openapi'; // Extended Zod instance

const users = sqliteTable('users', {
  id: integer().primaryKey({ autoIncrement: true }),
  name: text().notNull(),
  age: integer().notNull()
});

const { createInsertSchema } = createSchemaFactory({ zodInstance: z });

const userInsertSchema = createInsertSchema(users, {
  // We can now use the extended instance
  name: (schema) => schema.openapi({ example: 'John' })
});
```

**Use case: Type coercion**

```ts copy
import { integer, sqliteTable } from 'drizzle-orm/sqlite-core';
import { createSchemaFactory } from 'drizzle-orm/zod';
import { z } from 'zod/v4';

const users = sqliteTable('users', {
  ...,
  createdAt: integer({ mode: 'timestamp' }).notNull()
});

const { createInsertSchema } = createSchemaFactory({
  // This configuration will only coerce dates. Set `coerce` to `true` to coerce all data types or specify others
  coerce: {
    date: true
  }
});

const userInsertSchema = createInsertSchema(users);
// The above is the same as this:
const userInsertSchema = z.object({
  ...,
  createdAt: z.coerce.date()
});
```

### Data type reference

```ts
sqlite.integer({ mode: 'boolean' });

// Schema
z.boolean();
```

```ts
sqlite.integer({ mode: 'timestamp' });
sqlite.integer({ mode: 'timestamp_ms' });

// Schema
z.date();
```

```ts
sqlite.numeric();
sqlite.text({ mode: 'text' });

// Schema
z.string();
```

```ts
sqlite.numeric({ mode: 'number' });

// Schema
z.number().min(-9_007_199_254_740_991).max(9_007_199_254_740_991); // Javascript min. and max. safe integers
```

```ts
sqlite.numeric({ mode: 'bigint' });

// Schema
z.bigint().min(-9_223_372_036_854_775_808n).max(9_223_372_036_854_775_807n); // 64-bit integer lower and upper limit
```

```ts
sqlite.text({ mode: 'text', length: ... });

// Schema
z.string().max(length);
```

```ts
sqlite.text({ mode: 'text', enum: ... });

// Schema
z.enum(enum);
```

```ts
sqlite.real();

// Schema
z.number().min(-140_737_488_355_328).max(140_737_488_355_327); // 48-bit integer lower and upper limit
```

```ts
sqlite.integer({ mode: 'number' });

// Schema
z.number().min(-9_007_199_254_740_991).max(9_007_199_254_740_991).int(); // Javascript min. and max. safe integers
```

```ts
sqlite.blob({ mode: 'bigint' });

// Schema
z.bigint().min(-9_223_372_036_854_775_808n).max(9_223_372_036_854_775_807n); // 64-bit integer lower and upper limit
```

```ts
sqlite.blob({ mode: 'json' });
sqlite.text({ mode: 'json' });

// Schema
z.union([z.union([z.string(), z.number(), z.boolean(), z.null()]), z.record(z.any()), z.array(z.any())]);
```

```ts
sqlite.blob({ mode: 'buffer' });

// Schema
z.custom<Buffer>((v) => v instanceof Buffer);
```


Source: https://orm.drizzle.team/docs/sustainability

import { Image } from "astro:assets";
import roman from "@/assets/images/core/roman.jpg";
import smm from "@/assets/images/core/smm.jpg";
import group from "@/assets/images/core/group.jpeg";
import alex_sherman from "@/assets/images/core/alex_sherman.jpg";
import reka from "@/assets/images/team/reka.png";
import andrew from "@/assets/images/core/andrew.jpeg";
import blokh from "@/assets/images/core/blokh.jpeg";
import dan from "@/assets/images/core/dan.jpeg";

# Drizzle Sustainability

We've been building Drizzle since 2021, and while the project has gone through a few evolutions (and emotional breakdowns)
the core idea and vision never changed.

Throughout the years we've got 100+ sponsors, from awesome individuals to great companies supporting our work

As of March 2026 PlanetScale hired entire Drizzle core team and becomes the biggest backer we have!

They hired the whole team so we can keep working on Drizzle full-time, keep cooking on the roadmap,
ship more improvements, and continue building all the ambitious stuff we've wanted to bring to the community.

After a lot of great conversations with the PlanetScale team and Sam Lambert, we all came to the same conclusion:
the best way to make Drizzle the most sustainablest ORM on Earth was to just join forces.

So now PlanetScale is our biggest sponsor, they hired us, and we get to keep doing what we love:

- building for the community,
- obsessing over DX,
- and making SQL and Databases way to fun an easy to work with

## Our Team

So here we are, all core drizzle team members

<Image src={group} alt="group" />

#### But let's talk about each of us:

<style>{`
  .team-member {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 1.5rem;
    margin: 2rem 0;
  }

  .team-member__info {
    flex: 0 0 50%;
    max-width: 50%;
    min-width: 0;
    display: flex;
    flex-direction: column;
    justify-content: flex-start;
  }

  .team-member__name {
    margin-top: 0 !important;
    margin-bottom: 0.75rem;
  }

  .team-member__photo {
    width: 100%;
    max-width: 50%;
    flex: 0 0 50%;
    border-radius: 12px;
  }

  @media (max-width: 900px) {
    .team-member {
      flex-direction: column-reverse;
      gap: 1rem;
    }

    .team-member__photo {
      width: 100%;
      max-width: 320px;
      flex: 0 0 auto;
      align-self: center;
    }

    .team-member__info {
      max-width: 100%;
      flex: 0 0 auto;
    }
  }
`}</style>

<section class="team-member">
  <div class="team-member__info">
    <h4 class="team-member__name">Oleksandr Blokh (Alex)</h4>
    <p>
      Alex co-created Drizzle and helped start the Drizzle team. He's been here
      since 2021, when the first code was written for <code>drizzle-orm</code>.
    </p>
    <p>
      Now he leads core Drizzle development and works on Drizzle Studio,
      OneDollarStats, RubberBoots, and other projects.
    </p>
    <p>
      Give him a sub <a href="https://x.com/_alexblokh">on X</a> •{" "}
      <a href="https://github.com/AlexBlokh">GitHub</a>
    </p>
  </div>
  <Image
    class="team-member__photo"
    src={blokh}
    alt="Oleksandr Blokh"
    width={400}
  />
</section>

<section class="team-member">
  <div class="team-member__info">
    <h4 class="team-member__name">Andrii Sherman (Andrew)</h4>
    <p>
      Andrew is another Drizzle co-creator and co-founder. Back in 2020, he
      wrote a Drizzle ORM in Java. Later, seeing the need for the same kind of
      tool in the TypeScript world, he and Alex pivoted it to TypeScript. That's
      where it all started.
    </p>
    <p>
      Give him a sub <a href="https://x.com/andrii_sherman">on X</a> •{" "}
      <a href="https://github.com/AndriiSherman">GitHub</a>
    </p>
  </div>
  <Image
    class="team-member__photo"
    src={andrew}
    alt="Andrii Sherman"
    width={400}
  />
</section>

<section class="team-member">
  <div class="team-member__info">
    <h4 class="team-member__name">Dan Kochetov</h4>
    <p>
      Dan was the first to take on a full <code>drizzle-orm</code> rewrite and
      turn it into the API you know today. He also created the first version of
      Relational Queries.
    </p>
    <p>
      Now, after a short break, Dan is back in action and ready to ship more
      great things for Drizzle.
    </p>
    <p>
      Give him a sub <a href="https://x.com/bloberenober">on X</a> •{" "}
      <a href="https://github.com/dankochetov">GitHub</a>
    </p>
  </div>
  <Image class="team-member__photo" src={dan} alt="Dan Kochetov" width={400} />
</section>

<section class="team-member">
  <div class="team-member__info">
    <h4 class="team-member__name">Roman Nabukhotnyi (Zeus)</h4>
    <p>
      Roman (Zeus) is working hard to bring Drizzle Studio to you in every
      possible form.
    </p>
    <p>
      Roman is writing a lot about Drizzle Studio{" "}
      <a href="https://x.com/nabukhotnyi">on X</a> •
      <a href="https://github.com/RomanNabukhotnyi">GitHub</a>
    </p>
  </div>
  <Image
    class="team-member__photo"
    src={roman}
    alt="Roman Nabukhontyi"
    width={400}
  />
</section>

<section class="team-member">
  <div class="team-member__info">
    <h4 class="team-member__name">Serhii Reka</h4>
    <p>
      Serhii rewrote Relational Queries, mastered TypeScript types at the
      highest level, and continues shipping great features to the{" "}
      <code>drizzle</code> ecosystem.
    </p>
    <p>
      Give him a sub <a href="https://x.com/s_reka_">on X</a> •{" "}
      <a href="https://github.com/Sukairo-02">GitHub</a>
    </p>
  </div>
  <Image class="team-member__photo" src={reka} alt="Serhii Reka" width={400} />
</section>

<section class="team-member">
  <div class="team-member__info">
    <h4 class="team-member__name">Oleksandr Sherman</h4>
    <p>
      Oleksandr ("Sania") is a <code>drizzle-kit</code> wizard. He helped
      rewrite the
      <code>alternation-engine</code>, the drizzle-kit test suite, and is now on
      a mission to make sure there are 0 GitHub issues left with the{" "}
      <code>drizzle-kit</code> tag.
    </p>
    <p>
      Give him a sub <a href="https://x.com/_alex_sherman">on X</a> •{" "}
      <a href="https://github.com/AleksandrSherman">GitHub</a>
    </p>
  </div>
  <Image
    class="team-member__photo"
    src={alex_sherman}
    alt="Oleksandr Sherman"
    width={400}
  />
</section>

<section class="team-member">
  <div class="team-member__info">
    <h4 class="team-member__name">SMM Manager</h4>
    <p>
      "I'm now professionally responsible for what used to happen on X for free"
      (c)
    </p>
    <p>
      Give him a sub: <a href="https://x.com/DrizzleOrm">X</a>
    </p>
  </div>
  <Image class="team-member__photo" src={smm} alt="SMM Manager" width={400} />
</section>

## Revenue flow

Drizzle is not only `drizzle-orm` repository, we have a different set of products we've built and monetize

#### Drizzle Studio

Drizzle Studio is a web based modern database browser which comes in a form of:

1. [Drizzle Studio for Local Development](https://orm.drizzle.team/drizzle-studio/overview) for your Drizzle ORM projects
2. [Drizzle Studio Chrome Extension](https://driz.link/extension) which lets you browse PlanetScale, Cloudflare D1, Vercel Postgres and AWS Data API directly in their native consoles
3. [Drizzle Studio Gateway](https://gateway.drizzle.team) is a deployable Dockerized version of Studio on steroids, which you can put into your infrastructure and connect privately to your databases
4. `Drizzle Studio embeddable Component` - is a pre-bundled framework agnostic web component of Drizzle Studio which you can embed into your UI(React/Vue/Svelte/VanillaJS/whatever)

#### OneDollarStats

As with everything we ship, analytics is a product we originally built for our own use across different commercial projects.
We found a way to make it this affordable and bring it to the community, so you don't need to spend a lot on web analytics.

We've priced it at $1/mo with no limits for now, and we'll soon introduce usage-based pricing

https://onedollarstats.com/

#### Rubber Boots

Something we didn't release yet

## Drizzle LLC

Drizzle is a legal entity based in Ukraine.
Besides the 5 core Drizzle team members, we also have 18 more developers working with us on different production-grade apps in outsourcing and consulting.

This actually helps us build Drizzle in two big ways.

- First, it gives us another source of income, which means we can keep reinvesting into open-source work, testing new ideas, and pushing Drizzle forward.
- Second, it gives us a ton of real-world experience. We work on all kinds of projects (web, mobile, desktop, etc) across different languages, with a big focus on TypeScript.
  That also means we get hands-on experience with lots of frameworks, hosting platforms, and different ways people build and ship products.

A big reason Drizzle became what it is today is because we never locked ourselves into building just one thing. We're constantly
working on different kinds of projects, and that gives us new ideas, a broader perspective, and the kind of experience that helps us
build Drizzle in a way it is right now


Source: https://orm.drizzle.team/docs/tutorials

import Tutorials from "@components/Tutorials.astro";

<Tutorials/>

Source: https://orm.drizzle.team/docs/tutorials/bun-railway-pg


import Prerequisites from "@mdx/Prerequisites.astro";
import Npm from "@mdx/Npm.astro";
import Steps from "@mdx/Steps.astro";
import Section from "@mdx/Section.astro";
import Callout from "@mdx/Callout.astro";
import Shortcut from "@mdx/Shortcut.astro";

This tutorial demonstrates how to use Drizzle ORM with [Bun](https://bun.sh/) runtime and a PostgreSQL database, all deployed on [Railway](https://driz.link/railway).

<Prerequisites>
  - You should have [Bun](https://bun.sh/) installed. You can install it by following the [official guide](https://bun.sh/docs/installation).

  - You should have installed Drizzle ORM and [Drizzle kit](/docs/kit-overview). You can do this by running the following command:
  <Npm>
      drizzle-orm@rc
      -D drizzle-kit@rc
  </Npm>

  - You should have installed the `pg` package as the PostgreSQL driver.
  <Npm>
    pg
    -D @types/pg
  </Npm>

  - You should have a [Railway](https://driz.link/railway) account.
</Prerequisites>

## Setup Railway and Drizzle ORM

<Steps>
#### Create a Railway project

Log in to your [Railway dashboard](https://railway.app/dashboard) and click the `New Project` button.

![](@/assets/images/tutorials/railway-create-service-menu.png)

#### Provision a PostgreSQL database

On the project canvas, click the `New` button in the top right corner and select `Database` → `PostgreSQL`. You can also use the command palette (<Shortcut mac="⌘ K" other="Ctrl K" />) and search for PostgreSQL. Railway will provision a new PostgreSQL instance for you.

![](@/assets/images/tutorials/railway-select-postgres.png)

#### Enable public access on the database

By default, Railway keeps the database on the private network, so you cannot reach it from your machine. Click on the PostgreSQL service, go to the `Settings` tab, find the `Networking` section, and click `Add Public Access`.

![](@/assets/images/tutorials/railway-add-public-access.png)

Then click `Deploy` in the top bar to apply the change. Railway adds a public host and port, and sets the `DATABASE_PUBLIC_URL` variable on the service.

![](@/assets/images/tutorials/railway-add-public-access-apply.png)

#### Get your connection string

Go to the `Variables` tab of the PostgreSQL service and find the `DATABASE_PUBLIC_URL` variable. Copy the value — it should look similar to this:

```bash
postgresql://postgres:password@region.railway.app:port/railway
```

![](@/assets/images/tutorials/railway-postgres-variables.png)

<Callout type="warning">
Railway provides two types of database connection URLs:

- **Public URL** — accessible from anywhere (your local machine, external services). Uses a TCP proxy and looks like `postgresql://postgres:password@region.railway.app:port/railway`.
- **Private URL** — only accessible from services within the same Railway project via internal networking. Uses `*.railway.internal` hostname.

For **local development** (like running `drizzle-kit push` or `drizzle-kit studio`), you must use the **public URL**. The private `*.railway.internal` hostname will not resolve from your local machine.
</Callout>

#### Setup connection string variable

Create a `.env` file in the root of your project and add the `DATABASE_URL` environment variable. Use the **public** connection string from Railway:

```plaintext copy
DATABASE_URL=postgresql://postgres:password@region.railway.app:port/railway
```

<Callout type="info">
  This `.env` file is for local development only. When deploying to Railway, you
  will configure the `DATABASE_URL` environment variable separately in the
  Railway dashboard using a service reference variable.
</Callout>

#### Connect Drizzle ORM to your database

Create a `db.ts` file and set up your database configuration:

```typescript copy filename="src/db.ts"
import { drizzle } from "drizzle-orm/node-postgres";

export const db = drizzle(process.env.DATABASE_URL!);
```

#### Create tables

Create a `schema.ts` file and declare your tables:

```typescript copy filename="src/schema.ts"
import * as p from "drizzle-orm/pg-core";

export const usersTable = p.pgTable("users", {
  id: p.serial().primaryKey(),
  name: p.text().notNull(),
  age: p.integer().notNull(),
  email: p.text().notNull().unique(),
});

export const postsTable = p.pgTable("posts", {
  id: p.serial().primaryKey(),
  title: p.text().notNull(),
  content: p.text().notNull(),
  userId: p
    .integer()
    .notNull()
    .references(() => usersTable.id, { onDelete: "cascade" }),
  createdAt: p.timestamp().notNull().defaultNow(),
  updatedAt: p
    .timestamp()
    .notNull()
    .$onUpdate(() => new Date()),
});

export type InsertUser = typeof usersTable.$inferInsert;
export type SelectUser = typeof usersTable.$inferSelect;

export type InsertPost = typeof postsTable.$inferInsert;
export type SelectPost = typeof postsTable.$inferSelect;
```

#### Setup Drizzle config file

**Drizzle config** - a configuration file that is used by [Drizzle Kit](/docs/kit-overview) and contains all the information about your database connection, migration folder and schema files.

Create a `drizzle.config.ts` file in the root of your project and add the following content:

```typescript copy filename="drizzle.config.ts"
import { defineConfig } from "drizzle-kit";

export default defineConfig({
  schema: "./src/schema.ts",
  out: "./migrations",
  dialect: "postgresql",
  dbCredentials: {
    url: process.env.DATABASE_URL!,
  },
});
```

#### Applying changes to the database

You can generate migrations using `drizzle-kit generate` command and then run them using the `drizzle-kit migrate` command.

Generate migrations:

```bash copy
bunx drizzle-kit generate
```

The `generate` command only creates migration SQL files based on your schema — it does **not** apply any changes to the database. These migrations are stored in the `migrations` directory, as specified in your `drizzle.config.ts`. This directory will contain the SQL files necessary to update your database schema and a `meta` folder for storing snapshots of the schema at different migration stages.

Example of a generated migration:

```sql
CREATE TABLE "posts" (
	"id" serial PRIMARY KEY NOT NULL,
	"title" text NOT NULL,
	"content" text NOT NULL,
	"userId" integer NOT NULL,
	"createdAt" timestamp DEFAULT now() NOT NULL,
	"updatedAt" timestamp NOT NULL
);
--> statement-breakpoint
CREATE TABLE "users" (
	"id" serial PRIMARY KEY NOT NULL,
	"name" text NOT NULL,
	"age" integer NOT NULL,
	"email" text NOT NULL,
	CONSTRAINT "users_email_unique" UNIQUE("email")
);
--> statement-breakpoint
ALTER TABLE "posts" ADD CONSTRAINT "posts_userId_users_id_fk" FOREIGN KEY ("userId") REFERENCES "public"."users"("id") ON DELETE cascade ON UPDATE no action;
```

Apply the generated migrations to the database:

```bash copy
bunx drizzle-kit migrate
```

<Callout type="info">
  In this tutorial, migrations are applied automatically on application startup
  using `migrate()` from `drizzle-orm/node-postgres/migrator`. You can also
  apply them manually with `drizzle-kit migrate` for local testing.
</Callout>

Alternatively, you can push changes directly to the database using [Drizzle kit push command](/docs/kit-overview#prototyping-with-db-push):

```bash copy
bunx drizzle-kit push
```

<Callout type="warning">
  Push command is good for rapid prototyping in local development, allowing fast
  iterations without managing migration files. For production deployments,
  prefer the `generate` + `migrate` workflow to keep a versioned history of
  schema changes.
</Callout>

</Steps>

## Basic file structure

This is the basic file structure of the project. In the `src` directory, we have database-related files including connection in `db.ts` and schema definitions in `schema.ts`.

```plaintext
📦 <project root>
 ├ 📂 src
 │  ├ 📜 db.ts
 │  ├ 📜 schema.ts
 │  └ 📜 index.ts
 ├ 📂 migrations
 │  ├ 📂 meta
 │  │  ├ 📜 _journal.json
 │  │  └ 📜 0000_snapshot.json
 │  └ 📜 0000_whole_nomad.sql
 ├ 📜 .env
 ├ 📜 drizzle.config.ts
 ├ 📜 package.json
 └ 📜 tsconfig.json
```

## Deploy the App to Railway

<Steps>
#### Prepare your project for deployment

Once you've [generated your migrations](#applying-changes-to-the-database), commit the `migrations` directory to your repository — these files will be applied automatically when your app starts.

Create an `index.ts` file as the entry point for your application. This example runs migrations on startup and then starts a simple HTTP server using Bun:

```typescript copy filename="src/index.ts"
import { drizzle } from "drizzle-orm/node-postgres";
import { migrate } from "drizzle-orm/node-postgres/migrator";
import { usersTable } from "./schema";

const db = drizzle(process.env.DATABASE_URL!);

await migrate(db, { migrationsFolder: "./migrations" });

const server = Bun.serve({
  port: process.env.PORT || 3000,
  async fetch(req) {
    const url = new URL(req.url);

    if (url.pathname === "/users") {
      const users = await db.select().from(usersTable);
      return new Response(JSON.stringify(users), {
        headers: { "Content-Type": "application/json" },
      });
    }

    return new Response("OK");
  },
});

console.log(`Server running on port ${server.port}`);
```

The `migrate()` function reads the SQL files from your `migrations` directory and applies any unapplied migrations to the database. It is safe to run on every startup — already applied migrations are skipped.

Make sure your `package.json` has a start script:

```json copy filename="package.json"
{
  "scripts": {
    "start": "bun src/index.ts"
  }
}
```

#### Push your project to GitHub

Railway deploys from a GitHub repository. Initialize a git repository and push your code:

```bash copy
git init
git add .
git commit -m "initial commit"
```

Create a new repository on GitHub and push your code to it.

#### Connect your GitHub repository to Railway

In your Railway project, click the `New` button in the top right corner of the canvas and select `GitHub Repo`. Connect your GitHub account if prompted, then select the repository you just pushed.

![](@/assets/images/tutorials/railway-canvas-postgres-add-service.png)

![](@/assets/images/tutorials/bun-railway-github-repo-search.png)

#### Configure environment variables

In the deployed service settings, go to the `Variables` tab. Add the `DATABASE_URL` variable by referencing the PostgreSQL service variable:

Click `Add Variable`, set the name to `DATABASE_URL`, and use the Railway variable reference `${{Postgres.DATABASE_URL}}` as the value.

<Callout type="info">
The `${{Postgres.DATABASE_URL}}` reference variable automatically resolves to the **private** internal connection string at runtime, which is optimal for service-to-service communication within Railway. This is different from the public URL you use in your local `.env` file.
</Callout>

![](@/assets/images/tutorials/bun-railway-app-set-database-url.png)

#### Deploy

Railway will automatically deploy your application when you push to the connected branch. You can monitor the deployment in the `Deployments` tab.

![](@/assets/images/tutorials/bun-railway-deployment-successful.png)

#### Verify your setup

Once deployed, navigate to the `Architecture` tab in your Railway project. You should see your application service connected to the PostgreSQL database.

![](@/assets/images/tutorials/bun-railway-canvas-app-postgres.png)

<Callout type="warning" title="Alternative: Zero-downtime migrations">
This tutorial applies migrations at application startup using `migrate()`. This is the simplest approach and works well for most applications.

If you need **zero-downtime deployments**, you may want to run migrations as a **separate step** before the new version of your app starts receiving traffic. This way you can rollback the application independently from the database changes.

On Railway, you can achieve this using a [pre-deploy command](https://docs.railway.com/deployments/pre-deploy-command) — it runs between the build and deploy phases, has access to your private network and environment variables, and if it fails, the deployment will not proceed.

In your service settings, scroll down to the **Deploy** section and click **Add pre-deploy step**:

![](@/assets/images/tutorials/bun-railway-app-predeploy-migrate.png)

Enter the following command:

```bash copy
bunx drizzle-kit migrate
```

With this approach, remove the `await migrate(db, { migrationsFolder: "./migrations" })` call from your `index.ts` — migrations are handled by the pre-deploy command instead.

For more details, see the [Drizzle migrations fundamentals](/docs/migrations) page.

</Callout>

</Steps>

## Deploy Drizzle Studio to Railway

You can deploy [Drizzle Studio](/drizzle-studio/overview) alongside your application on Railway to browse and manage your database directly from the browser.

### Option 1: one-click deployment (recommended)

<a
  href="https://railway.com/new/template/drizzle-studio-1?referralCode=eobqmj&utm_medium=integration&utm_source=button&utm_campaign=drizzle-studio-1"
  target="_blank"
  rel="nofollow noreferrer"
  style="display: inline-block; margin: 16px 0;"
>
  <img src="https://railway.com/button.svg" alt="Deploy on Railway" width="183" height="40" />
</a>

<Steps>
#### Choose your Railway project

Open the `Deploy to` dropdown and select the project that holds your PostgreSQL database. Deploying into the same project lets Drizzle Studio reference the database variables.

![](@/assets/images/tutorials/railway-deploy-drizzle-studio-project.png)

#### Set the database connection string

Click `Configure`, set the `DATABASE_URL` variable to `${{Postgres.DATABASE_URL}}` to reference your existing PostgreSQL service, and click `Save Config`. Then click `Review and deploy`.

![](@/assets/images/tutorials/railway-deploy-drizzle-studio-env.png)

</Steps>

### Option 2: manual deployment

<details>
<summary style="cursor: pointer; user-select: none; margin-bottom: 16px;">Show the manual steps</summary>

<Steps>
#### Add a new service from a template

In your Railway project, click the `New` button in the top right corner of the canvas and select `Template`.

![](@/assets/images/tutorials/bun-railway-canvas-postgres-add-new-service.png)

#### Select the Drizzle Studio template

Search for `drizzle studio` and select the **Drizzle Studio** template by Drizzle.

![](@/assets/images/tutorials/railway-template-search-drizzle-studio.png)

#### Configure environment variables and deploy

The template comes with three pre-configured environment variables:

- `PASSCODE` - the password for secure access to your Studio instance. It defaults to `${{secret()}}`, which generates a random secret.
- `DATABASE_URL` - the database connection string. Set it to `${{Postgres.DATABASE_URL}}` to reference your existing PostgreSQL service.
- `PORT` - the port Drizzle Studio listens on. It defaults to `4983`. Leave it as it is.

Click `Deploy Template` to deploy.

![](@/assets/images/tutorials/railway-drizzle-studio-template-config.png)

</Steps>

</details>

### After deployment

<Steps>
#### Find your Drizzle Studio URL

Once deployed, click on the Drizzle Studio service in your project, go to the `Settings` tab, and scroll down to the `Networking` section. You will find your public domain under **Public Networking**.

![](@/assets/images/tutorials/railway-drizzle-studio-networking.png)

#### Enter the passcode

Open the Drizzle Studio URL in your browser. On the first visit it asks for a passcode.

![](@/assets/images/tutorials/railway-drizzle-studio-passcode-request.png)

Go back to the Drizzle Studio service in Railway, open the `Variables` tab, and copy the value of the `PASSCODE` variable. The template generates it for you, so it is different for every deployment.

![](@/assets/images/tutorials/railway-drizzle-studio-passcode.png)

Paste the value into the prompt and click `Continue`.

#### Browse your database with Drizzle Studio

You should now see your database tables and can browse, filter, and edit data directly.

![](@/assets/images/tutorials/drizzle-studio-posts-table.png)

#### Verify your setup

Navigate to the `Architecture` tab in your Railway project. You should now see three services: your application, the PostgreSQL database, and Drizzle Studio.

![](@/assets/images/tutorials/bun-railway-canvas-all-services.png)

</Steps>


Source: https://orm.drizzle.team/docs/tutorials/drizzle-nextjs-neon


import Steps from "@mdx/Steps.astro";
import Npm from "@mdx/Npm.astro";
import CodeTabs from "@mdx/CodeTabs.astro";
import CodeTab from "@mdx/CodeTab.astro";
import Section from "@mdx/Section.astro";
import Tabs from "@mdx/Tabs.astro";
import Tab from "@mdx/Tab.astro";
import Prerequisites from "@mdx/Prerequisites.astro";
import Callout from "@mdx/Callout.astro";

This tutorial demonstrates how to build `Todo app` using **Drizzle ORM** with **Neon database** and **Next.js**.

<Prerequisites>  
  - You should have an existing Next.js project or create a new one using the following command:
  ```bash
  npx create-next-app@latest --typescript
  ```

  - You should have installed Drizzle ORM and [Drizzle kit](/docs/kit-overview). You can do this by running the following command:
  <Npm>
      drizzle-orm@rc
      -D drizzle-kit@rc
  </Npm>

  - You should have installed the [Neon serverless driver](https://neon.tech/docs/serverless/serverless-driver). 
  <Npm>
    @neondatabase/serverless
  </Npm>

  - You should have installed the `dotenv` package for managing environment variables. 
  <Npm>
    dotenv
  </Npm>  
</Prerequisites>

<Callout type="warning">
In case you face the issue with resolving dependencies during installation:

If you're not using React Native, forcing the installation with `--force` or `--legacy-peer-deps` should resolve the issue. If you are using React Native, then you need to use the exact version of React which is compatible with your React Native version.
</Callout>

## Setup Neon and Drizzle ORM

<Steps>
#### Create a new Neon project

Log in to the [Neon Console](https://console.neon.tech/app/projects) and navigate to the Projects section. Select a project or click the `New Project` button to create a new one. 

Your Neon projects come with a ready-to-use Postgres database named `neondb`. We'll use it in this tutorial.

#### Setup connection string variable

Navigate to the **Connection Details** section in the project console to find your database connection string. It should look similar to this:

```bash
postgres://username:password@ep-cool-darkness-123456.us-east-2.aws.neon.tech/neondb
```

Add the `DATABASE_URL` environment variable to your `.env` or `.env.local` file, which you'll use to connect to the Neon database.

```bash
DATABASE_URL=NEON_DATABASE_CONNECTION_STRING
```

#### Connect Drizzle ORM to your database 

Create a `drizzle.ts` file in your `src/db` folder and set up your database configuration:

```tsx copy filename="src/db/drizzle.ts"
import { config } from "dotenv";
import { drizzle } from 'drizzle-orm/neon-http';

config({ path: ".env" }); // or .env.local

export const db = drizzle(process.env.DATABASE_URL!);
```

#### Declare todo schema

```tsx copy filename="src/db/schema.ts"
import { integer, text, boolean, pgTable } from "drizzle-orm/pg-core";

export const todo = pgTable("todo", {
  id: integer("id").primaryKey(),
  text: text("text").notNull(),
  done: boolean("done").default(false).notNull(),
});
```

Here we define the **`todo`** table with fields **`id`**, **`text`**, and **`done`**, using data types from Drizzle ORM.

#### Setup Drizzle config file

**Drizzle config** - a configuration file that is used by [Drizzle Kit](/docs/kit-overview) and contains all the information about your database connection, migration folder and schema files.

Create a `drizzle.config.ts` file in the root of your project and add the following content:

```typescript copy filename="drizzle.config.ts"
import { config } from 'dotenv';
import { defineConfig } from "drizzle-kit";

config({ path: '.env' });

export default defineConfig({
  schema: "./src/db/schema.ts",
  out: "./migrations",
  dialect: "postgresql",
  dbCredentials: {
    url: process.env.DATABASE_URL!,
  },
});
```

#### Applying changes to the database

You can generate migrations using `drizzle-kit generate` command and then run them using the `drizzle-kit migrate` command.

Generate migrations:

```bash
npx drizzle-kit generate
```

These migrations are stored in the `drizzle/migrations`  directory, as specified in your `drizzle.config.ts`. This directory will contain the SQL files necessary to update your database schema and a `meta` folder for storing snapshots of the schema at different migration stages.

Example of a generated migration:

```sql
CREATE TABLE IF NOT EXISTS "todo" (
	"id" integer PRIMARY KEY NOT NULL,
	"text" text NOT NULL,
	"done" boolean DEFAULT false NOT NULL
);
```

Run migrations:

```bash
npx drizzle-kit migrate
```

Alternatively, you can push changes directly to the database using [Drizzle kit push command](/docs/kit-overview#prototyping-with-db-push):

```bash
npx drizzle-kit push
```

<Callout type="warning">Push command is good for situations where you need to quickly test new schema designs or changes in a local development environment, allowing for fast iterations without the overhead of managing migration files.</Callout>
</Steps>

#### Establish server-side functions
In this step, we establish server-side functions in the **src/actions/todoAction.ts** file to handle crucial operations on todo items:

1. **`getData`:**
    - Fetches all existing todo items from the database.
2. **`addTodo`:**
    - Adds a new todo item to the database with the provided text.
    - Initiates revalidation of the home page using **`revalidatePath("/")`**.
3. **`deleteTodo`:**
    - Removes a todo item from the database based on its unique ID.
    - Triggers a revalidation of the home page.
4. **`toggleTodo`:**
    - Toggles the completion status of a todo item, updating the database accordingly.
    - Revalidates the home page after the operation.
5. **`editTodo`:**
    - Modifies the text of a todo item identified by its ID in the database.
    - Initiates a revalidation of the home page.

```tsx collapsable copy filename="src/actions/todoAction.ts"
"use server";
import { eq, not } from "drizzle-orm";
import { revalidatePath } from "next/cache";
import { db } from "@/db/drizzle";
import { todo } from "@/db/schema";

export const getData = async () => {
  const data = await db.select().from(todo);
  return data;
};

export const addTodo = async (id: number, text: string) => {
  await db.insert(todo).values({
    id: id,
    text: text,
  });
};

export const deleteTodo = async (id: number) => {
  await db.delete(todo).where(eq(todo.id, id));

  revalidatePath("/");
};

export const toggleTodo = async (id: number) => {
  await db
    .update(todo)
    .set({
      done: not(todo.done),
    })
    .where(eq(todo.id, id));

  revalidatePath("/");
};

export const editTodo = async (id: number, text: string) => {
  await db
    .update(todo)
    .set({
      text: text,
    })
    .where(eq(todo.id, id));

  revalidatePath("/");
};
```

## Setup home page with Next.js

<Steps>
#### Define a TypeScript type

Define a TypeScript type for a todo item in `src/types/todoType.ts` with three properties: **`id`** of type **`number`**, **`text`** of type **`string`**, and **`done`** of type **`boolean`**. This type, named **`todoType`**, represents the structure of a typical todo item within your application.

```ts copy filename="src/types/todoType.ts"
export type todoType = {
  id: number;
  text: string;
  done: boolean;
};
```

#### Create a home page for a to-do application

1. **`src/components/todo.tsx`:**
    Create a `Todo` component that represents a single todo item. It includes features for displaying and editing the todo text, marking it as done with a checkbox, and providing actions for editing, saving, canceling, and deleting the todo.
2. **`src/components/addTodo.tsx`:**
    The `AddTodo` component provides a simple form for adding new todo items to the Todo app. It includes an input field for entering the todo text and a button for triggering the addition of the new todo.
3. **`src/components/todos.tsx`:**
    Create Todos components that represents the main interface of a Todo app. It manages the state of todo items, provides functions for creating, editing, toggling, and deleting todos, and renders the individual todo items using the `Todo` component.

<CodeTabs items={["todo.tsx", "addTodo.tsx", "todos.tsx"]}>
```tsx collapsable copy
"use client";
import { ChangeEvent, FC, useState } from "react";
import { todoType } from "@/types/todoType";

interface Props {
  todo: todoType;
  changeTodoText: (id: number, text: string) => void;
  toggleIsTodoDone: (id: number, done: boolean) => void;
  deleteTodoItem: (id: number) => void;
}

const Todo: FC<Props> = ({
  todo,
  changeTodoText,
  toggleIsTodoDone,
  deleteTodoItem,
}) => {
  // State for handling editing mode
  const [editing, setEditing] = useState(false);

  // State for handling text input
  const [text, setText] = useState(todo.text);

  // State for handling "done" status
  const [isDone, setIsDone] = useState(todo.done);

  // Event handler for text input change
  const handleTextChange = (e: ChangeEvent<HTMLInputElement>) => {
    setText(e.target.value);
  };

  // Event handler for toggling "done" status
  const handleIsDone = async () => {
    toggleIsTodoDone(todo.id, !isDone);
    setIsDone((prev) => !prev);
  };

  // Event handler for initiating the edit mode
  const handleEdit = () => {
    setEditing(true);
  };

  // Event handler for saving the edited text
  const handleSave = async () => {
    changeTodoText(todo.id, text);
    setEditing(false);
  };

  // Event handler for canceling the edit mode
  const handleCancel = () => {
    setEditing(false);
    setText(todo.text);
  };

  // Event handler for deleting a todo item
  const handleDelete = () => {
    if (confirm("Are you sure you want to delete this todo?")) {
      deleteTodoItem(todo.id);
    }
  };

  // Rendering the Todo component
  return (
    <div className="flex items-center gap-2 p-4 border-gray-200 border-solid border rounded-lg">
      {/* Checkbox for marking the todo as done */}
      <input
        type="checkbox"
        className="text-blue-200 rounded-sm h-4 w-4"
        checked={isDone}
        onChange={handleIsDone}
      />
      {/* Input field for todo text */}
      <input
        type="text"
        value={text}
        onChange={handleTextChange}
        readOnly={!editing}
        className={`${
          todo.done ? "line-through" : ""
        } outline-none read-only:border-transparent focus:border border-gray-200 rounded px-2 py-1 w-full`}
      />
      {/* Action buttons for editing, saving, canceling, and deleting */}
      <div className="flex gap-1 ml-auto">
        {editing ? (
          <button
            onClick={handleSave}
            className="bg-green-600 text-green-50 rounded px-2 w-14 py-1"
          >
            Save
          </button>
        ) : (
          <button
            onClick={handleEdit}
            className="bg-blue-400 text-blue-50 rounded w-14 px-2 py-1"
          >
            Edit
          </button>
        )}
        {editing ? (
          <button
            onClick={handleCancel}
            className="bg-red-400 w-16 text-red-50 rounded px-2 py-1"
          >
            Close
          </button>
        ) : (
          <button
            onClick={handleDelete}
            className="bg-red-400 w-16 text-red-50 rounded px-2 py-1"
          >
            Delete
          </button>
        )}
      </div>
    </div>
  );
};

export default Todo;
```
```tsx collapsable copy
"use client";
import { ChangeEvent, FC, useState } from "react";

interface Props {
  createTodo: (value: string) => void;
}

const AddTodo: FC<Props> = ({ createTodo }) => {
  // State for handling input value
  const [input, setInput] = useState("");

  // Event handler for input change
  const handleInput = (e: ChangeEvent<HTMLInputElement>) => {
    setInput(e.target.value);
  };

  // Event handler for adding a new todo
  const handleAdd = async () => {
    createTodo(input);
    setInput("");
  };

  // Rendering the AddTodo component
  return (
    <div className="w-full flex gap-1 mt-2">
      {/* Input field for entering new todo text */}
      <input
        type="text"
        className="w-full px-2 py-1 border border-gray-200 rounded outline-none"
        onChange={handleInput}
        value={input}
      />
      {/* Button for adding a new todo */}
      <button
        className="flex items-center justify-center bg-green-600 text-green-50 rounded px-2 h-9 w-14 py-1"
        onClick={handleAdd}
      >
        Add
      </button>
    </div>
  );
};

export default AddTodo;
```

	<CodeTab>
```tsx collapsable copy
"use client";
import { FC, useState } from "react";
import { todoType } from "@/types/todoType";
import Todo from "./todo";
import AddTodo from "./addTodo";
import { addTodo, deleteTodo, editTodo, toggleTodo } from "@/actions/todoAction";

interface Props {
  todos: todoType[];
}

const Todos: FC<Props> = ({ todos }) => {
  // State to manage the list of todo items
  const [todoItems, setTodoItems] = useState<todoType[]>(todos);

  // Function to create a new todo item
  const createTodo = (text: string) => {
    const id = (todoItems.at(-1)?.id || 0) + 1;
    addTodo(id, text);
    setTodoItems((prev) => [...prev, { id: id, text, done: false }]);
  };

  // Function to change the text of a todo item
  const changeTodoText = (id: number, text: string) => {
    setTodoItems((prev) =>
      prev.map((todo) => (todo.id === id ? { ...todo, text } : todo))
    );
    editTodo(id, text);
  };

  // Function to toggle the "done" status of a todo item
  const toggleIsTodoDone = (id: number) => {
    setTodoItems((prev) =>
      prev.map((todo) => (todo.id === id ? { ...todo, done: !todo.done } : todo))
    );
    toggleTodo(id);
  };

  // Function to delete a todo item
  const deleteTodoItem = (id: number) => {
    setTodoItems((prev) => prev.filter((todo) => todo.id !== id));
    deleteTodo(id);
  };

  // Rendering the Todo List component
  return (
    <main className="flex mx-auto max-w-xl w-full min-h-screen flex-col items-center p-16">
      <div className="text-5xl font-medium">To-do app</div>
      <div className="w-full flex flex-col mt-8 gap-2">
        {/* Mapping through todoItems and rendering Todo component for each */}
        {todoItems.map((todo) => (
          <Todo
            key={todo.id}
            todo={todo}
            changeTodoText={changeTodoText}
            toggleIsTodoDone={toggleIsTodoDone}
            deleteTodoItem={deleteTodoItem}
          />
        ))}
      </div>
      {/* Adding Todo component for creating new todos */}
      <AddTodo createTodo={createTodo} />
    </main>
  );
};

export default Todos;
```

    </CodeTab>
</CodeTabs>

Update the `page.tsx` file in the `src/app` folder to fetch the todo items from the database and render the `Todos` component:

```tsx copy filename="src/app/page.tsx"
import { getData } from "@/actions/todoAction";
import Todos from "@/components/todos";

export default async function Home() {
  const data = await getData();
  return <Todos todos={data} />;
}
```
</Steps>

## Basic file structure

This guide uses the following file structure:

```text
📦 <project root>
 ├ 📂 migrations
 │  ├ 📂 meta
 │  └ 📜 0000_heavy_doctor_doom.sql
 ├ 📂 public
 ├ 📂 src
 │  ├ 📂 actions
 │  │  └ 📜 todoActions.ts
 │  ├ 📂 app
 │  │  ├ 📜 favicon.ico
 │  │  ├ 📜 globals.css
 │  │  ├ 📜 layout.tsx
 │  │  └ 📜 page.tsx
 │  ├ 📂 components
 │  │  ├ 📜 addTodo.tsx
 │  │  ├ 📜 todo.tsx
 │  │  └ 📜 todos.tsx
 │  └ 📂 db
 │  │  ├ 📜 drizzle.ts
 │  │  └ 📜 schema.ts
 │  └ 📂 types
 │     └ 📜 todoType.ts
 ├ 📜 .env
 ├ 📜 .eslintrc.json
 ├ 📜 .gitignore
 ├ 📜 drizzle.config.ts
 ├ 📜 next-env.d.ts
 ├ 📜 next.config.mjs
 ├ 📜 package-lock.json
 ├ 📜 package.json
 ├ 📜 postcss.config.mjs
 ├ 📜 README.md
 ├ 📜 tailwind.config.ts
 └ 📜 tsconfig.json
```


Source: https://orm.drizzle.team/docs/tutorials/drizzle-with-encore


import Steps from "@mdx/Steps.astro";
import Npm from "@mdx/Npm.astro";
import CodeTabs from "@mdx/CodeTabs.astro";
import CodeTab from "@mdx/CodeTab.astro";
import Section from "@mdx/Section.astro";
import Callout from "@mdx/Callout.astro";
import Prerequisites from "@mdx/Prerequisites.astro";

This tutorial demonstrates how to use **Drizzle ORM** with **Encore**, an open source backend framework with built-in infrastructure automation and observability.

<Prerequisites>
  - You should have the Encore CLI installed. You can install it with:
  ```bash
  # macOS
  brew install encoredev/tap/encore

  # Linux
  curl -L https://encore.dev/install.sh | bash

  # Windows
  iwr https://encore.dev/install.ps1 | iex
  ```

  - You should have installed Drizzle ORM and [Drizzle kit](/docs/kit-overview). You can do this by running the following command:
  <Npm>
      drizzle-orm@rc
      -D drizzle-kit@rc
  </Npm>
</Prerequisites>

## Setup Encore and Drizzle ORM

<Steps>
#### Create a new Encore project

You can create a new Encore project with Drizzle already configured:

```bash
encore app create my-app --example=ts/drizzle
cd my-app
```

Or if you have an existing Encore project, install Drizzle:

<Npm>
    drizzle-orm@rc
    -D drizzle-kit@rc
</Npm>

#### Create the database

Define your database in a `database.ts` file. Encore automatically provisions a PostgreSQL database locally using Docker and in the cloud when you deploy:

```typescript copy filename="database.ts"
import { SQLDatabase } from "encore.dev/storage/sqldb";
import { drizzle } from "drizzle-orm/node-postgres";
import * as schema from "./schema";

const db = new SQLDatabase("mydb", {
  migrations: {
    path: "migrations",
    source: "drizzle",
  },
});

export const orm = drizzle(db.connectionString, { schema });
```

Setting `source: "drizzle"` tells Encore to use Drizzle's migration format.

#### Define your schema

Create a `schema.ts` file to define your tables:

```typescript copy filename="schema.ts"
import * as p from "drizzle-orm/pg-core";

export const users = p.pgTable("users", {
  id: p.serial().primaryKey(),
  name: p.text().notNull(),
  email: p.text().unique().notNull(),
  createdAt: p.timestamp().defaultNow().notNull(),
});
```

#### Setup Drizzle config

Create a `drizzle.config.ts` file:

```typescript copy filename="drizzle.config.ts"
import { defineConfig } from "drizzle-kit";

export default defineConfig({
  out: "migrations",
  schema: "schema.ts",
  dialect: "postgresql",
});
```

#### Generate migrations

Run Drizzle Kit to generate migrations from your schema:

```bash
drizzle-kit generate
```

This creates migration files in the `migrations` folder.

#### Create an API endpoint

Use Drizzle in your Encore endpoints:

```typescript copy filename="users.ts"
import { api } from "encore.dev/api";
import { orm } from "./database";
import { users } from "./schema";
import { eq } from "drizzle-orm";

interface User {
  id: number;
  name: string;
  email: string;
}

export const list = api(
  { expose: true, method: "GET", path: "/users" },
  async (): Promise<{ users: User[] }> => {
    const result = await orm.select().from(users);
    return { users: result };
  }
);

export const create = api(
  { expose: true, method: "POST", path: "/users" },
  async (req: { name: string; email: string }): Promise<User> => {
    const [user] = await orm
      .insert(users)
      .values({ name: req.name, email: req.email })
      .returning();
    return user;
  }
);
```

#### Run your application

Start your Encore app:

```bash
encore run
```

Encore automatically applies migrations when starting. Open [localhost:9400](http://localhost:9400) to see the local dashboard with API docs, database explorer, and tracing.
</Steps>

<Callout type="info">
Migrations are automatically applied when you run your Encore application. You don't need to run `drizzle-kit migrate` manually.
</Callout>

## Learn more

- [Encore Documentation](https://encore.dev/docs)
- [Encore Drizzle Guide](https://encore.dev/docs/ts/develop/orms/drizzle)
- [Drizzle ORM Documentation](/docs/overview)


Source: https://orm.drizzle.team/docs/tutorials/drizzle-with-neon


import Prerequisites from "@mdx/Prerequisites.astro";
import Npm from "@mdx/Npm.astro";
import Steps from "@mdx/Steps.astro";
import Section from "@mdx/Section.astro";
import Callout from "@mdx/Callout.astro";

This tutorial demonstrates how to use Drizzle ORM with [Neon Postgres](https://neon.tech/) database. If you do not have an existing Neon account, sign up [here](https://neon.tech). 

<Prerequisites>  
  - You should have installed Drizzle ORM and [Drizzle kit](/docs/kit-overview). You can do this by running the following command:
  <Npm>
      drizzle-orm@rc
      -D drizzle-kit@rc
  </Npm>

  - You should also install the [Neon serverless driver](https://neon.tech/docs/serverless/serverless-driver). 
  <Npm>
    @neondatabase/serverless
  </Npm>
  
  - You should have installed the `dotenv` package for managing environment variables. 
  <Npm>
    dotenv
  </Npm>  
</Prerequisites>

## Setup Neon and Drizzle ORM

<Steps>
#### Create a new Neon project

Log in to the [Neon Console](https://console.neon.tech/app/projects) and navigate to the Projects section. Select a project or click the `New Project` button to create a new one. 

Your Neon projects come with a ready-to-use Postgres database named `neondb`. We'll use it in this tutorial.

#### Setup connection string variable

Navigate to the **Connection Details** section in the project console to find your database connection string. It should look similar to this:

```bash
postgres://username:password@ep-cool-darkness-123456.us-east-2.aws.neon.tech/neondb
```

Add the `DATABASE_URL` environment variable to your `.env` or `.env.local` file, which you'll use to connect to the Neon database.

```text copy
DATABASE_URL=NEON_DATABASE_CONNECTION_STRING
```

#### Connect Drizzle ORM to your database 

Create a `db.ts` file and set up your database configuration:

```typescript copy filename="src/db.ts"
import { drizzle } from "drizzle-orm/neon-http";
import { neon } from "@neondatabase/serverless";
import { config } from "dotenv";

config({ path: ".env" }); // or .env.local

const sql = neon(process.env.DATABASE_URL!);
export const db = drizzle({ client: sql });
```

#### Create tables

Create a `schema.ts` file and declare your tables:

```typescript copy filename="src/schema.ts"
import { integer, pgTable, serial, text, timestamp } from 'drizzle-orm/pg-core';

export const usersTable = pgTable('users_table', {
  id: serial('id').primaryKey(),
  name: text('name').notNull(),
  age: integer('age').notNull(),
  email: text('email').notNull().unique(),
});

export const postsTable = pgTable('posts_table', {
  id: serial('id').primaryKey(),
  title: text('title').notNull(),
  content: text('content').notNull(),
  userId: integer('user_id')
    .notNull()
    .references(() => usersTable.id, { onDelete: 'cascade' }),
  createdAt: timestamp('created_at').notNull().defaultNow(),
  updatedAt: timestamp('updated_at')
    .notNull()
    .$onUpdate(() => new Date()),
});

export type InsertUser = typeof usersTable.$inferInsert;
export type SelectUser = typeof usersTable.$inferSelect;

export type InsertPost = typeof postsTable.$inferInsert;
export type SelectPost = typeof postsTable.$inferSelect;
```

#### Setup Drizzle config file

**Drizzle config** - a configuration file that is used by [Drizzle Kit](/docs/kit-overview) and contains all the information about your database connection, migration folder and schema files.

Create a `drizzle.config.ts` file in the root of your project and add the following content:

```typescript copy filename="drizzle.config.ts"
import { config } from 'dotenv';
import { defineConfig } from "drizzle-kit";

config({ path: '.env' });

export default defineConfig({
  schema: "./src/schema.ts",
  out: "./migrations",
  dialect: "postgresql",
  dbCredentials: {
    url: process.env.DATABASE_URL!,
  },
});
```

#### Applying changes to the database

You can generate migrations using `drizzle-kit generate` command and then run them using the `drizzle-kit migrate` command.

Generate migrations:

```bash copy
npx drizzle-kit generate
```

These migrations are stored in the `drizzle/migrations`  directory, as specified in your `drizzle.config.ts`. This directory will contain the SQL files necessary to update your database schema and a `meta` folder for storing snapshots of the schema at different migration stages.

Example of a generated migration:

```sql
CREATE TABLE IF NOT EXISTS "posts_table" (
	"id" serial PRIMARY KEY NOT NULL,
	"title" text NOT NULL,
	"content" text NOT NULL,
	"user_id" integer NOT NULL,
	"created_at" timestamp DEFAULT now() NOT NULL,
	"updated_at" timestamp NOT NULL
);
--> statement-breakpoint
CREATE TABLE IF NOT EXISTS "users_table" (
	"id" serial PRIMARY KEY NOT NULL,
	"name" text NOT NULL,
	"age" integer NOT NULL,
	"email" text NOT NULL,
	CONSTRAINT "users_table_email_unique" UNIQUE("email")
);
--> statement-breakpoint
DO $$ BEGIN
 ALTER TABLE "posts_table" ADD CONSTRAINT "posts_table_user_id_users_table_id_fk" FOREIGN KEY ("user_id") REFERENCES "public"."users_table"("id") ON DELETE cascade ON UPDATE no action;
EXCEPTION
 WHEN duplicate_object THEN null;
END $$;
```

Run migrations:

```bash copy
npx drizzle-kit migrate
```

Alternatively, you can push changes directly to the database using [Drizzle kit push command](/docs/kit-overview#prototyping-with-db-push):

```bash copy
npx drizzle-kit push
```

<Callout type="warning">Push command is good for situations where you need to quickly test new schema designs or changes in a local development environment, allowing for fast iterations without the overhead of managing migration files.</Callout>

</Steps>

### Basic file structure

This is the basic file structure of the project. In the `src/db` directory, we have database-related files including connection in `db.ts`, schema definitions in `schema.ts`, and a migration script in `migrate.ts` file which is responsible for applying migrations that stored in the `migrations` directory.

```plaintext
📦 <project root>
 ├ 📂 src
 │  ├ 📜 db.ts
 │  └ 📜 schema.ts
 ├ 📂 migrations
 │  ├ 📂 meta
 │  │  ├ 📜 _journal.json
 │  │  └ 📜 0000_snapshot.json
 │  └ 📜 0000_dry_richard_fisk.sql
 ├ 📜 .env
 ├ 📜 drizzle.config.ts
 ├ 📜 package.json
 └ 📜 tsconfig.json
```

## Query examples

For instance, we create `src/queries` folder and separate files for each operation: insert, select, update, delete.

#### Insert data

Read more about insert query in the [documentation](/docs/insert).

```typescript copy filename="src/queries/insert.ts" {4, 8}
import { db } from '../db';
import { InsertPost, InsertUser, postsTable, usersTable } from '../schema';

export async function createUser(data: InsertUser) {
  await db.insert(usersTable).values(data);
}

export async function createPost(data: InsertPost) {
  await db.insert(postsTable).values(data);
}
```

#### Select data

Read more about select query in the [documentation](/docs/select).

<Callout type='warning'>
`getColumns` available starting from `drizzle-orm@1.0.0-beta.2`(read more [here](/docs/upgrade-v1))

If you are on pre-1 version(like `0.45.1`) then use `getTableColumns`
</Callout>

```typescript copy filename="src/queries/select.ts" {5, 16, 41}
import { asc, between, count, eq, getColumns, sql } from 'drizzle-orm';
import { db } from '../db';
import { SelectUser, usersTable, postsTable } from '../schema';

export async function getUserById(id: SelectUser['id']): Promise<
  Array<{
    id: number;
    name: string;
    age: number;
    email: string;
  }>
> {
  return db.select().from(usersTable).where(eq(usersTable.id, id));
}

export async function getUsersWithPostsCount(
  page = 1,
  pageSize = 5,
): Promise<
  Array<{
    postsCount: number;
    id: number;
    name: string;
    age: number;
    email: string;
  }>
> {
  return db
    .select({
      ...getColumns(usersTable),
      postsCount: count(postsTable.id),
    })
    .from(usersTable)
    .leftJoin(postsTable, eq(usersTable.id, postsTable.userId))
    .groupBy(usersTable.id)
    .orderBy(asc(usersTable.id))
    .limit(pageSize)
    .offset((page - 1) * pageSize);
}

export async function getPostsForLast24Hours(
  page = 1,
  pageSize = 5,
): Promise<
  Array<{
    id: number;
    title: string;
  }>
> {
  return db
    .select({
      id: postsTable.id,
      title: postsTable.title,
    })
    .from(postsTable)
    .where(between(postsTable.createdAt, sql`now() - interval '1 day'`, sql`now()`))
    .orderBy(asc(postsTable.title), asc(postsTable.id))
    .limit(pageSize)
    .offset((page - 1) * pageSize);
}
```

Alternatively, you can use [relational query syntax](/docs/rqb).

#### Update data

Read more about update query in the [documentation](/docs/update).

```typescript copy filename="src/queries/update.ts" {5}
import { eq } from 'drizzle-orm';
import { db } from '../db';
import { SelectPost, postsTable } from '../schema';

export async function updatePost(id: SelectPost['id'], data: Partial<Omit<SelectPost, 'id'>>) {
  await db.update(postsTable).set(data).where(eq(postsTable.id, id));
}
```

#### Delete data

Read more about delete query in the [documentation](/docs/delete).

```typescript copy filename="src/queries/delete.ts" {5}
import { db } from '../db';
import { eq } from 'drizzle-orm';
import { SelectUser, usersTable } from '../schema';

export async function deleteUser(id: SelectUser['id']) {
  await db.delete(usersTable).where(eq(usersTable.id, id));
}
```


Source: https://orm.drizzle.team/docs/tutorials/drizzle-with-netlify-edge-functions-neon


import Prerequisites from "@mdx/Prerequisites.astro";
import Npm from '@mdx/Npm.astro';
import Steps from '@mdx/Steps.astro';
import Section from "@mdx/Section.astro";
import Callout from "@mdx/Callout.astro";

This tutorial demonstrates how to use Drizzle ORM with [Netlify Edge Functions](https://docs.netlify.com/edge-functions/overview/) and [Neon Postgres](https://neon.tech/) database.

<Prerequisites>
- You should have the latest version of [Netlify CLI](https://docs.netlify.com/cli/get-started/#installation) installed.
- You should have installed Drizzle ORM and [Drizzle kit](/docs/kit-overview). You can do this by running the following command:
<Npm>
  drizzle-orm@rc
  -D drizzle-kit@rc
</Npm>

- You should have installed the `dotenv` package for managing environment variables. If you use Node.js `v20.6.0` or later, there is no need to install it because Node.js natively supports `.env` files. Read more about it [here](https://nodejs.org/en/blog/release/v20.6.0#built-in-env-file-support).
<Npm>
  dotenv
</Npm>

- Optionally, you can install the `@netlify/edge-functions` package to import the types for the `Context` object which will be used later.
<Npm>
  @netlify/edge-functions
</Npm>
</Prerequisites>

<Callout type="warning">
These installed packages are used only to create table in the database in [Create a table](#create-a-table), [Setup Drizzle config file](#setup-drizzle-config-file) and [Apply changes to the database](#apply-changes-to-the-database) steps. These packages do not affect the code running inside Netlify Edge Functions. We will use `import_map.json` to import the necessary packages for the Edge Functions.
</Callout>

<Steps>
#### Setup Neon Postgres

Log in to the [Neon Console](https://console.neon.tech/app/projects) and navigate to the Projects section. Select a project or click the `New Project` button to create a new one. 

Your Neon projects come with a ready-to-use Postgres database named `neondb`. We'll use it in this tutorial.

#### Setup connection string variable

In **Project Dashboard** section click the `Connect` button and copy your database connection string. It should look similar to this:

```bash
postgres://username:password@ep-cool-darkness-123456.us-east-2.aws.neon.tech/neondb?sslmode=require
```

Add the `DATABASE_URL` environment variable to your `.env` file, which you'll use to connect to the Neon database.

```text copy
DATABASE_URL=NEON_DATABASE_CONNECTION_STRING
```

#### Setup Netlify Edge Functions

Create `netlify/edge-functions` directory in the root of your project. This is where you'll store your Edge Functions.

Create a function `user.ts` in the `netlify/edge-functions` directory.

```typescript copy filename="netlify/edge-functions/user.ts"
import type { Context } from "@netlify/edge-functions";

export default async (request: Request, context: Context) => {
  return new Response("User data");
};
```

<Callout type="warning">
The types for the `Request` and `Response` objects are in the global scope.
</Callout>

#### Setup imports

Create a `import_map.json` file in the root of your project and add the following content:

```json copy filename="import_map.json"
{
  "imports": {
    "drizzle-orm/": "https://esm.sh/drizzle-orm/",
    "@neondatabase/serverless": "https://esm.sh/@neondatabase/serverless"
  }
}
```

Read more about `import_map.json` in Netlify Edge Functions [here](https://docs.netlify.com/edge-functions/api/#import-maps).

#### Create a Netlify configuration file

Create a `netlify.toml` file in the root of your project and add the following content:

```toml copy filename="netlify.toml"
[functions]
  deno_import_map = "./import_map.json"

[[edge_functions]]
  path = "/user"
  function = "user"
```

This configuration tells Netlify to use the `import_map.json` file for Deno imports and to route requests to the `/user` path to the `user.ts` function. 
Read more about `netlify.toml` [here](https://docs.netlify.com/configure-builds/file-based-configuration/).

#### Create a table

Create a `schema.ts` file in the `netlify/edge-functions/common` directory and declare a table schema:

```typescript copy filename="netlify/edge-functions/common/schema.ts"
import { pgTable, serial, text, integer } from "drizzle-orm/pg-core";

export const usersTable = pgTable('users_table', {
  id: serial('id').primaryKey(),
  name: text('name').notNull(),
  age: integer('age').notNull(),
  email: text('email').notNull().unique(),
})
```

#### Setup Drizzle config file

**Drizzle config** - a configuration file that is used by [Drizzle Kit](/docs/kit-overview) and contains all the information about your database connection, migration folder and schema files.

Create a `drizzle.config.ts` file in the root of your project and add the following content:

```typescript copy filename="drizzle.config.ts"
import 'dotenv/config'; // remove this line if you use Node.js v20.6.0 or later
import type { Config } from "drizzle-kit";

export default {
  schema: './netlify/edge-functions/common/schema.ts',
  out: './drizzle',
  dialect: 'postgresql',
  dbCredentials: {
    url: process.env.DATABASE_URL!,
  },
} satisfies Config;
```

In this tutorial we will use Drizzle kit to push changes to the Neon database.

#### Apply changes to the database

```bash copy
npx drizzle-kit push
```
<Callout type="warning">Push command is good for situations where you need to quickly test new schema designs or changes in a local development environment, allowing for fast iterations without the overhead of managing migration files.</Callout>

Alternatively, you can use migrations workflow. Read about it here: [Migrations](/docs/migrations).

#### Connect Drizzle ORM to your database

Update your `netlify/edge-functions/user.ts` file and set up your database configuration:

```typescript copy filename="netlify/edge-functions/user.ts"
import type { Context } from "@netlify/edge-functions";
import { usersTable } from "./common/schema.ts";
import { neon } from '@neondatabase/serverless';
import { drizzle } from 'drizzle-orm/neon-http';

export default async (request: Request, context: Context) => {
  const sql = neon(Netlify.env.get("DATABASE_URL")!);
  const db = drizzle({ client: sql });

  const users = await db.select().from(usersTable);

  return new Response(JSON.stringify(users));
};
```

<Callout type="warning">
You might see a red underline under the imports if you're using VS Code. The Edge Function will still execute. To get rid of the red underline, you can configure VS Code to use Edge Functions in the next step.
</Callout>

#### Test your code locally

Run the following command to start the Netlify dev server:

```bash copy
netlify dev
```

When you first run the command it will suggest to configure VS Code to use Edge Functions. Click `Yes` to configure it. `settings.json` file will be created in the `.vscode` directory.
If you still see red underlines, you can restart the Deno Language Server.

Open your browser and navigate to the route `/user`. You should see the user data returned from the Neon database:

```plaintext
[]
```

It could be an empty array if you haven't added any data to the `users_table` table.

#### Initialize a new Netlify project

Run the following command to initialize a new Netlify project:

```bash copy
netlify init
```

Answer the questions in the CLI to create a new Netlify project. In this tutorial, we will choose `Yes, create and deploy site manually` -> `<YOUR_TEAM>` -> `<SITE_NAME>`.

#### Setup Netlify environment variables

Run the following command to import your environment variables into Netlify:

```bash copy
netlify env:import .env
```

Read more about Netlify environment variables [here](https://docs.netlify.com/environment-variables/get-started/).

#### Deploy your project

Run the following command to deploy your project:

```bash copy
netlify deploy
```

Follow the instructions in the CLI to deploy your project to Netlify. In this tutorial our publish directory is `'.'`.

It is a [draft deployment](https://docs.netlify.com/cli/get-started/#draft-deploys) by default.
To do a production deployment, run the following command:

```bash copy
netlify deploy --prod
```

</Steps>

Finally, you can use URL of the deployed website and navigate to the route you created `(e.g. /user)` to access your edge function.


Source: https://orm.drizzle.team/docs/tutorials/drizzle-with-netlify-edge-functions-supabase


import Prerequisites from "@mdx/Prerequisites.astro";
import Npm from '@mdx/Npm.astro';
import Steps from '@mdx/Steps.astro';
import Section from "@mdx/Section.astro";
import Callout from "@mdx/Callout.astro";

This tutorial demonstrates how to use Drizzle ORM with [Netlify Edge Functions](https://docs.netlify.com/edge-functions/overview/) and [Supabase Database](https://supabase.com/docs/guides/database/overview) database.

<Prerequisites>
- You should have the latest version of [Netlify CLI](https://docs.netlify.com/cli/get-started/#installation) installed.
- You should have installed Drizzle ORM and [Drizzle kit](/docs/kit-overview). You can do this by running the following command:
<Npm>
  drizzle-orm@rc
  -D drizzle-kit@rc
</Npm>

- You should have installed the `dotenv` package for managing environment variables. If you use Node.js `v20.6.0` or later, there is no need to install it because Node.js natively supports `.env` files. Read more about it [here](https://nodejs.org/en/blog/release/v20.6.0#built-in-env-file-support).
<Npm>
  dotenv
</Npm>

- Optionally, you can install the `@netlify/edge-functions` package to import the types for the `Context` object which will be used later.
<Npm>
  @netlify/edge-functions
</Npm>
</Prerequisites>

<Callout type="warning">
These installed packages are used only to create table in the database in [Create a table](#create-a-table), [Setup Drizzle config file](#setup-drizzle-config-file) and [Apply changes to the database](#apply-changes-to-the-database) steps. These packages do not affect the code running inside Netlify Edge Functions. We will use `import_map.json` to import the necessary packages for the Edge Functions.
</Callout>

<Steps>
#### Create a new Supabase project

You can create new Supabase project in the [dashboard](https://supabase.com/dashboard) or by following this [link](https://database.new/).

#### Setup connection string variable

You can find `Project connect details` by clicking **Connect** in the top bar of the dashboard and copy the URI from the `Transaction pooler` section. Remember to replace the password placeholder with your actual database password.

Add `DATABASE_URL` variable to your `.env` file.

```plaintext copy
DATABASE_URL=<YOUR_DATABASE_URL>
```

Read more about connecting to Supabase Database in the [documentation](https://supabase.com/docs/guides/database/connecting-to-postgres#connection-pooler).

#### Setup Netlify Edge Functions

Create `netlify/edge-functions` directory in the root of your project. This is where you'll store your Edge Functions.

Create a function `user.ts` in the `netlify/edge-functions` directory.

```typescript copy filename="netlify/edge-functions/user.ts"
import type { Context } from "@netlify/edge-functions";

export default async (request: Request, context: Context) => {
  return new Response("User data");
};
```

<Callout type="warning">
The types for the `Request` and `Response` objects are in the global scope.
</Callout>

#### Setup imports

Create a `import_map.json` file in the root of your project and add the following content:

```json copy filename="import_map.json"
{
  "imports": {
    "drizzle-orm/": "https://esm.sh/drizzle-orm/",
    "postgres": "https://esm.sh/postgres"
  }
}
```

Read more about `import_map.json` in Netlify Edge Functions [here](https://docs.netlify.com/edge-functions/api/#import-maps).

#### Create a Netlify configuration file

Create a `netlify.toml` file in the root of your project and add the following content:

```toml copy filename="netlify.toml"
[functions]
  deno_import_map = "./import_map.json"

[[edge_functions]]
  path = "/user"
  function = "user"
```

This configuration tells Netlify to use the `import_map.json` file for Deno imports and to route requests to the `/user` path to the `user.ts` function. 
Read more about `netlify.toml` [here](https://docs.netlify.com/configure-builds/file-based-configuration/).

#### Create a table

Create a `schema.ts` file in the `netlify/edge-functions/common` directory and declare a table schema:

```typescript copy filename="netlify/edge-functions/common/schema.ts"
import { pgTable, serial, text, integer } from "drizzle-orm/pg-core";

export const usersTable = pgTable('users_table', {
  id: serial('id').primaryKey(),
  name: text('name').notNull(),
  age: integer('age').notNull(),
  email: text('email').notNull().unique(),
})
```

#### Setup Drizzle config file

**Drizzle config** - a configuration file that is used by [Drizzle Kit](/docs/kit-overview) and contains all the information about your database connection, migration folder and schema files.

Create a `drizzle.config.ts` file in the root of your project and add the following content:

```typescript copy filename="drizzle.config.ts"
import 'dotenv/config'; // remove this line if you use Node.js v20.6.0 or later
import type { Config } from "drizzle-kit";

export default {
  schema: './netlify/edge-functions/common/schema.ts',
  out: './drizzle',
  dialect: 'postgresql',
  dbCredentials: {
    url: process.env.DATABASE_URL!,
  },
} satisfies Config;
```

In this tutorial we will use Drizzle kit to push changes to the Neon database.

#### Apply changes to the database

```bash copy
npx drizzle-kit push
```
<Callout type="warning">Push command is good for situations where you need to quickly test new schema designs or changes in a local development environment, allowing for fast iterations without the overhead of managing migration files.</Callout>

Alternatively, you can use migrations workflow. Read about it here: [Migrations](/docs/migrations).

#### Connect Drizzle ORM to your database

Update your `netlify/edge-functions/user.ts` file and set up your database configuration:

```typescript copy filename="netlify/edge-functions/user.ts"
import type { Context } from "@netlify/edge-functions";
import { usersTable } from "./common/schema.ts";
import { drizzle } from 'drizzle-orm/postgres-js';
import postgres from 'postgres';

export default async (request: Request, context: Context) => {
  const queryClient = postgres(Netlify.env.get("DATABASE_URL")!);
  const db = drizzle({ client: queryClient });

  const users = await db.select().from(usersTable);

  return new Response(JSON.stringify(users));
};
```

<Callout type="warning">
You might see a red underline under the imports if you're using VS Code. The Edge Function will still execute. To get rid of the red underline, you can configure VS Code to use Edge Functions in the next step.
</Callout>

#### Test your code locally

Run the following command to start the Netlify dev server:

```bash copy
netlify dev
```

When you first run the command it will suggest to configure VS Code to use Edge Functions. Click `Yes` to configure it. `settings.json` file will be created in the `.vscode` directory.
If you still see red underlines, you can restart the Deno Language Server.

Open your browser and navigate to the route `/user`. You should see the user data returned from the Neon database:

```plaintext
[]
```

It could be an empty array if you haven't added any data to the `users_table` table.

#### Initialize a new Netlify project

Run the following command to initialize a new Netlify project:

```bash copy
netlify init
```

Answer the questions in the CLI to create a new Netlify project. In this tutorial, we will choose `Yes, create and deploy site manually` -> `<YOUR_TEAM>` -> `<SITE_NAME>`.

#### Setup Netlify environment variables

Run the following command to import your environment variables into Netlify:

```bash copy
netlify env:import .env
```

Read more about Netlify environment variables [here](https://docs.netlify.com/environment-variables/get-started/).

#### Deploy your project

Run the following command to deploy your project:

```bash copy
netlify deploy
```

Follow the instructions in the CLI to deploy your project to Netlify. In this tutorial our publish directory is `'.'`.

It is a [draft deployment](https://docs.netlify.com/cli/get-started/#draft-deploys) by default.
To do a production deployment, run the following command:

```bash copy
netlify deploy --prod
```

</Steps>

Finally, you can use URL of the deployed website and navigate to the route you created `(e.g. /user)` to access your edge function.


Source: https://orm.drizzle.team/docs/tutorials/drizzle-with-nile


import Prerequisites from "@mdx/Prerequisites.astro";
import Npm from '@mdx/Npm.astro';
import Steps from '@mdx/Steps.astro';
import Section from "@mdx/Section.astro";
import Callout from '@mdx/Callout.astro';
import TransferCode from '@mdx/get-started/TransferCode.mdx';
import ApplyChanges from '@mdx/get-started/ApplyChanges.mdx';
import RunFile from '@mdx/get-started/RunFile.mdx';

This tutorial demonstrates how to use Drizzle ORM with [Nile Database](https://thenile.dev). Nile is Postgres, re-engineered for multi-tenant applications. 

This tutorial will demonstrate how to use Drizzle with Nile's virtual tenant databases to developer a secure, scalable, multi-tenant application. 

We'll walk through building this example application step-by-step. If you want to peek at the complete example, you can take a look at its [Github repository](https://github.com/niledatabase/niledatabase/tree/main/examples/quickstart/drizzle).

<Prerequisites>
- You should have installed Drizzle ORM and [Drizzle kit](/docs/kit-overview). You can do this by running the following command:
<Npm>
  drizzle-orm@rc
  -D drizzle-kit@rc
</Npm>
- You should have installed `dotenv` package for managing environment variables. Read more about this package [here](https://www.npmjs.com/package/dotenv)
<Npm>
  dotenv
</Npm>
- You should have installed `node-postgres` package for connecting to the Postgres database. Read more about this package [here](https://www.npmjs.com/package/node-postgres)
<Npm>
  node-postgres
</Npm>
- You should have installed `express` package for the web framework. Read more about express [here](https://expressjs.com/)
<Npm>
  express
</Npm>

- This guide uses [AsyncLocalStorage](https://nodejs.org/api/async_context.html) to manage the tenant context. If your framework or runtime does not support `AsyncLocalStorage`, you can refer to [Drizzle\<\>Nile](/docs/connect-nile) doc for alternative options. 
</Prerequisites>

## Setup Nile and Drizzle ORM

<Steps>
#### Signup to Nile and create a database

If you haven't already, sign up to [Nile](https://console.thenile.dev) and follow the app instructions to create a new database.

#### Get database connection string

On the left side-bar menu, select the "Settings" option, click on the Postgres logo, and click "generate credentials". Copy the connection string and add it to the `.env` file in your project:

```plaintext copy
NILEDB_URL=postgres://youruser:yourpassword@us-west-2.db.thenile.dev:5432:5432/your_db_name
```

#### Connect Drizzle ORM to your database

Create a `db.ts` file in the `src/db` directory and set up your database configuration:

```typescript copy filename="src/db/db.ts"
import { drizzle } from 'drizzle-orm/node-postgres';
import dotenv from "dotenv/config";
import { sql } from "drizzle-orm";
import { AsyncLocalStorage } from "async_hooks";

export const db = drizzle(process.env.NILEDB_URL);
export const tenantContext = new AsyncLocalStorage<string | undefined>();

export function tenantDB<T>(cb: (tx: any) => T | Promise<T>): Promise<T> {
  return db.transaction(async (tx) => {
    const tenantId = tenantContext.getStore();
    console.log("executing query with tenant: " + tenantId);
    // if there's a tenant ID, set it in the transaction context
    if (tenantId) {
      await tx.execute(sql`set local nile.tenant_id = '${sql.raw(tenantId)}'`);
    }

    return cb(tx);
  }) as Promise<T>;
}
```

#### Setup Drizzle config file

**Drizzle config** - a configuration file that is used by [Drizzle Kit](/docs/kit-overview) and contains all the information about your database connection, migration folder and schema files.

Create a `drizzle.config.ts` file in the root of your project and add the following content:

```typescript copy filename="drizzle.config.ts"
import 'dotenv/config';
import { defineConfig } from 'drizzle-kit';
export default defineConfig({
  out: './drizzle',
  schema: './src/db/schema.ts',
  dialect: 'postgresql',
  dbCredentials: {
    url: process.env.NILEDB_URL!,
  },
});
```

#### Introspect Nile database

Nile databases have built-in tables. The most important of these is the `tenants` table, which is used to create and manage tenants. 
In order to use this table from our application, we'll use Drizzle Kit CLI to generate a schema file that includes this schema.

```bash copy
npx drizzle-kit pull
```

The result of introspection will be a `schema.ts` file, `meta` folder with snapshots of your database schema, sql file with the migration and `relations.ts` file for [relational queries](/docs/rqb).

<TransferCode/>

Here is an example of the generated `schema.ts` file:

```typescript copy filename="src/db/schema.ts"
// table schema generated by introspection
import { pgTable, uuid, text, timestamp, varchar, vector, boolean } from "drizzle-orm/pg-core"
import { sql } from "drizzle-orm"

export const tenants = pgTable("tenants", {
	id: uuid().default(sql`public.uuid_generate_v7()`).primaryKey().notNull(),
	name: text(),
	created: timestamp({ mode: 'string' }).default(sql`LOCALTIMESTAMP`).notNull(),
	updated: timestamp({ mode: 'string' }).default(sql`LOCALTIMESTAMP`).notNull(),
	deleted: timestamp({ mode: 'string' }),
});
```

#### Create additional tables

In addition to the built-in tables, our application will need some tables to store its data. We will add them to `src/db/schema.ts` that we previously generated, so this file will look like this:

```typescript copy filename="src/db/schema.ts"
// table schema generated by introspection
import { pgTable, uuid, text, timestamp, varchar, vector, boolean } from "drizzle-orm/pg-core"
import { sql } from "drizzle-orm"

export const tenants = pgTable("tenants", {
	id: uuid().default(sql`public.uuid_generate_v7()`).primaryKey().notNull(),
	name: text(),
	created: timestamp({ mode: 'string' }).default(sql`LOCALTIMESTAMP`).notNull(),
	updated: timestamp({ mode: 'string' }).default(sql`LOCALTIMESTAMP`).notNull(),
	deleted: timestamp({ mode: 'string' }),
});

export const todos = pgTable("todos", {
	id: uuid().defaultRandom(),
	tenantId: uuid("tenant_id"),
	title: varchar({ length: 256 }),
	estimate: varchar({ length: 256 }),
	embedding: vector({ dimensions: 3 }),
	complete: boolean(),
});
```

#### Apply changes to the database

<ApplyChanges />

#### Initialize the webapp

Now that we have set up Drizzle to connect to Nile and we have our schema in place, we can use them in a multi-tenant web application. 
We are using Express as the web framework in this example, although Nile and Drizzle can be used from any web framework.

To keep the example simple, we'll implement the webapp in a single file - `src/app.ts`. We'll start by initializing the webapp:

```typescript copy filename="src/app.ts"
import express from "express";
import { tenantDB, tenantContext, db } from "./db/db";
import {
  tenants as tenantSchema,
  todos as todoSchema,
} from "./db/schema";
import { eq } from "drizzle-orm";

const PORT = process.env.PORT || 3001;

const app = express();
app.listen(PORT, () => console.log(`Server is running on port ${PORT}`));
app.use(express.json());
```

#### Initialize the tenant-aware middleware

Next, we'll add middleware to the example. This middleware grabs the tenant ID from the path parameters and stores it in the `AsyncLocalStorage`. 
The `tenantDB` wrapper that we created in `src/db/index.ts` uses this tenant ID to set `nile.tenant_id` when executing queries, 
which then guarantees that the queries will execute against this tenant's virtual database.

```typescript copy filename="src/app.ts"
// set the tenant ID in the context based on the URL parameter
app.use('/api/tenants/:tenantId/*', (req, res, next) => {
  const tenantId = req.params.tenantId;
  console.log("setting context to tenant: " + tenantId);
  tenantContext.run(tenantId, next);
});
```

<Callout>
The example gets the tenant ID from path parameter, but it is also common to set the tenant ID in a header such as `x-tenant-id` or in a cookie.
</Callout>

#### Add routes

Lastly, we need to add some routes for creating and listing tenants and todos. Note how we are using `tenantDB` wrapper to connect to the tenant's virtual database.
Also note how in `app.get("/api/tenants/:tenantId/todos"` we did not need to specify `where tenant_id=...` in the query. 
This is exactly because we are routed to that tenant's database and the query cannot return data for any other tenant.

```typescript copy filename="src/app.ts" {6,20,39,58,62,75,83}
// create new tenant
app.post("/api/tenants", async (req, res) => {
  try {
    const name = req.body.name;
    var tenants: any = null;
    tenants = await tenantDB(async (tx) => {
        return await tx.insert(tenantSchema).values({ name }).returning();
    });
    res.json(tenants);
  } catch (error: any) {
    console.log("error creating tenant: " + error.message);
    res.status(500).json({message: "Internal Server Error",});
  }
});

// return list of tenants
app.get("/api/tenants", async (req, res) => {
  let tenants: any = [];
  try {
      tenants = await tenantDB(async (tx) => {
        return await tx.select().from(tenantSchema);
      });
    res.json(tenants);
  } catch (error: any) {
    console.log("error listing tenants: " + error.message);
    res.status(500).json({message: "Internal Server Error",});
  }
});

// add new task for tenant
app.post("/api/tenants/:tenantId/todos", async (req, res) => {
  try {
    const { title, complete } = req.body;
    if (!title) {
      res.status(400).json({message: "No task title provided",});
    }
    const tenantId = req.params.tenantId;

    const newTodo = await tenantDB(async (tx) => {
      return await tx
        .insert(todoSchema)
        .values({ tenantId, title, complete })
        .returning();
    });
    // return without the embedding vector, since it is huge and useless
    res.json(newTodo);
  } catch (error: any) {
    console.log("error adding task: " + error.message);
    res.status(500).json({message: "Internal Server Error",});
  }
});

// update tasks for tenant
// No need for where clause because we have the tenant in the context
app.put("/api/tenants/:tenantId/todos", async (req, res) => {
  try {
    const { id, complete } = req.body;
    await tenantDB(async (tx) => {
      return await tx
        .update(todoSchema)
        .set({ complete })
        .where(eq(todoSchema.id, id));
    });
    res.sendStatus(200);
  } catch (error: any) {
    console.log("error updating tasks: " + error.message);
    res.status(500).json({message: "Internal Server Error",});
  }
});

// get all tasks for tenant
app.get("/api/tenants/:tenantId/todos", async (req, res) => {
  try {
    // No need for a "where" clause here because we are setting the tenant ID in the context
    const todos = await tenantDB(async (tx) => {
      return await tx
        .select({
          id: todoSchema.id,
          tenant_id: todoSchema.tenantId,
          title: todoSchema.title,
          estimate: todoSchema.estimate,
        })
        .from(todoSchema);
    });
    res.json(todos);
  } catch (error: any) {
    console.log("error listing tasks: " + error.message);
    res.status(500).json({message: error.message,});
  }
});
```

#### Try it out!

You can now run your new web application:

```bash copy
npx tsx src/app.ts
```

and use `curl` to try the routes you just created:

```bash
# create a tenant
curl --location --request POST 'localhost:3001/api/tenants' \
--header 'Content-Type: application/json' \
--data-raw '{"name":"my first customer"}'

# get tenants
curl  -X GET 'http://localhost:3001/api/tenants'

# create a todo (don't forget to use a real tenant-id in the URL)
curl  -X POST \
  'http://localhost:3001/api/tenants/108124a5-2e34-418a-9735-b93082e9fbf2/todos' \
  --header 'Content-Type: application/json' \
  --data-raw '{"title": "feed the cat", "complete": false}'

# list todos for tenant (don't forget to use a real tenant-id in the URL)
curl  -X GET \
  'http://localhost:3001/api/tenants/108124a5-2e34-418a-9735-b93082e9fbf2/todos'
```
</Steps>

## Project file structure

This is the file structure of the project. In the `src/db` directory, we have database-related files including connection in `db.ts` and schema definitions 
in `schema.ts`. The files generated by the migrations and introspections are in `./drizzle`

```plaintext
📦 <project root>
 ├ 📂 src
 │   ├ 📂 db
 │   │  ├ 📜 db.ts
 │   │  └ 📜 schema.ts
 │   └ 📜 app.ts
 ├ 📂 drizzle
 │   ├ 📂 meta
 │   │  ├ 📜 _journal.json
 │   │  └ 📜 0000_snapshot.json
 │   ├ 📜 relations.ts
 │   ├ 📜 schema.ts
 │   └ 📜 0000_watery_spencer_smythe.sql
 ├ 📜 .env
 ├ 📜 drizzle.config.ts
 └ 📜 package.json
```


Source: https://orm.drizzle.team/docs/tutorials/drizzle-with-supabase-edge-functions


import Prerequisites from "@mdx/Prerequisites.astro";
import Npm from '@mdx/Npm.astro';
import Steps from '@mdx/Steps.astro';
import Section from "@mdx/Section.astro";
import Callout from '@mdx/Callout.astro';

This tutorial demonstrates how to use Drizzle ORM with [Supabase Edge Functions](https://supabase.com/docs/guides/functions).

<Prerequisites>
- You should have the latest version of [Supabase CLI](https://supabase.com/docs/guides/cli/getting-started#installing-the-supabase-cli) installed.
- You should have installed Drizzle ORM and [Drizzle kit](https://orm.drizzle.team/kit-docs/overview). You can do this by running the following command:
<Npm>
  drizzle-orm@rc
  -D drizzle-kit@rc
</Npm>
- You should have installed Docker Desktop. It is a prerequisite for local development. Follow the official [docs](https://docs.docker.com/desktop) to install.
</Prerequisites>

To learn how to create a basic Edge Function on your local machine and then deploy it, see the [Edge Functions Quickstart](https://supabase.com/docs/guides/functions/quickstart).

<Steps>
#### Create a table

Create a `schema.ts` file in your `src` directory and declare a table schema:

```typescript copy filename="src/schema.ts"
import { pgTable, serial, text, integer } from "drizzle-orm/pg-core";

export const usersTable = pgTable('users_table', {
  id: serial('id').primaryKey(),
  name: text('name').notNull(),
  age: integer('age').notNull()
})
```

This file will be used to generate migrations for your database.

#### Setup Drizzle config file

**Drizzle config** - a configuration file that is used by [Drizzle Kit](https://orm.drizzle.team/kit-docs/overview) and contains all the information about your database connection, migration folder and schema files.

Create a `drizzle.config.ts` file in the root of your project and add the following content:

```typescript copy filename="drizzle.config.ts"
import { defineConfig } from "drizzle-kit";

export default defineConfig({
  schema: "./src/schema.ts",
  out: "./supabase/migrations",
  dialect: "postgresql",
});
```

In this tutorial we will use Drizzle kit to generate migrations for our schema.

#### Initialize a new Supabase project

Create a new Supabase project in a folder on your local machine:

```bash copy
supabase init
```

It will create `supabase` folder with `config.toml` file:

```text
└── supabase
    └── config.toml
```

If you are using Visual Studio Code, follow the [Supabase documentation](https://supabase.com/docs/guides/functions/local-development#deno-with-visual-studio-code) to setup settings for Deno.

#### Generate migrations

Run the `drizzle-kit generate` command to generate migrations:

```bash copy
npx drizzle-kit generate
```

It will create a new migration file in the `supabase/migrations` directory:

#### Apply migrations

To start the Supabase local development stack, run the following command:

```bash copy
supabase start
```

To apply migrations, run the following command:

```bash copy
supabase migration up
```

You can read more about Supabase migrations in the [documentation](https://supabase.com/docs/guides/deployment/database-migrations).

<Callout type="warning">Don't forget to run Docker</Callout>

Alternatively, you can apply migrations using the `drizzle-kit migrate` command. Learn more about this migration process in the [documentation](https://orm.drizzle.team/docs/migrations).

#### Create a new Edge Function

Run the `supabase functions new [FUNCTION_NAME]` command to create a new Edge Function:

```bash copy
supabase functions new drizzle-tutorial
```

It will create a new folder with the function name in the `supabase/functions` directory:

```text
└── supabase
    └── functions
    │   └── drizzle-tutorial
    │   │   ├── .npmrc ## Function-specific npm configuration (if needed)
    │   │   ├── deno.json ## Function-specific Deno configuration
    │   │   └── index.ts ## Your function code
```

When you create a new Edge Function, it will use TypeScript by default. However, it is possible write Edge Function in JavaScript. Learn more about it in the [documentation](https://supabase.com/docs/guides/functions/quickstart#not-using-typescript).

#### Setup imports

Add the following imports to the `deno.json` file in the `supabase/functions/drizzle-tutorial` directory:

```json copy filename="supabase/functions/drizzle-tutorial/deno.json"
{
  "imports": {
    "drizzle-orm/": "npm:/drizzle-orm/",
    "postgres": "npm:postgres"
  }
}
```

You can read more about managing dependencies [here](https://supabase.com/docs/guides/functions/dependencies#managing-dependencies).

#### Copy your schema to the functions directory

Copy the code that you will use in your edge function from `src/schema.ts` file to the `supabase/functions/drizzle-tutorial/index.ts` file:

```typescript copy filename="supabase/functions/drizzle-tutorial/index.ts"
// Setup type definitions for built-in Supabase Runtime APIs
import "jsr:@supabase/functions-js/edge-runtime.d.ts"
import { pgTable, serial, text, integer } from "drizzle-orm/pg-core";

const usersTable = pgTable('users_table', {
  id: serial('id').primaryKey(),
  name: text('name').notNull(),
  age: integer('age').notNull()
})

Deno.serve(async (req) => {
  const { name } = await req.json()
  const data = {
    message: `Hello ${name}!`,
  }

  return new Response(
    JSON.stringify(data),
    { headers: { "Content-Type": "application/json" } },
  )
})  
```

<Callout type="warning">
In the Deno ecosystem, each function should be treated as an independent project with its own set of dependencies and configurations.
For these reasons, Supabase recommend maintaining separate configuration files (`deno.json`, `.npmrc`, or `import_map.json`) within each function's directory, even if it means duplicating some configurations. Read more [here](https://supabase.com/docs/guides/functions/dependencies#managing-dependencies).
</Callout>

#### Connect Drizzle ORM to your database

Update your edge function code with your database configuration:

```typescript copy filename="supabase/functions/drizzle-tutorial/index.ts" {14,17,18}
// Setup type definitions for built-in Supabase Runtime APIs
import { integer, pgTable, serial, text } from "drizzle-orm/pg-core";
import { drizzle } from "drizzle-orm/postgres-js";
import "jsr:@supabase/functions-js/edge-runtime.d.ts";
import postgres from "postgres";

const usersTable = pgTable('users_table', {
  id: serial('id').primaryKey(),
  name: text('name').notNull(),
  age: integer('age').notNull()
})

Deno.serve(async () => {
  const connectionString = Deno.env.get("SUPABASE_DB_URL")!;

  // Disable prefetch as it is not supported for "Transaction" pool mode
  const client = postgres(connectionString, { prepare: false });
  const db = drizzle({ client });

  await db.insert(usersTable).values({
    name: "Alice",
    age: 25
  })
  const data = await db.select().from(usersTable);

  return new Response(
    JSON.stringify(data)
  )
})
```

`SUPABASE_DB_URL` is default environment variable for the direct database connection. Learn more about managing environment variables in Supabase Edge Functions in the [documentation](https://supabase.com/docs/guides/functions/secrets).

#### Test your code locally

Run the following command to test your function locally:

```bash copy
supabase functions serve --no-verify-jwt
```

Navigate to the route `(e.g. /drizzle-tutorial)` in your browser:

```plaintext
[
  {
    "id": 1,
    "name": "Alice",
    "age": 25
  }
]
```

#### Link your local project to a hosted Supabase project

You can create new Supabase project in the [dashboard](https://supabase.com/dashboard) or by following this [link](https://database.new/).

Copy the `Reference ID` from project settings and use it to link your local development project to a hosted Supabase project by running the following command:

```bash copy
supabase link --project-ref=<REFERENCE_ID>
```

Push your schema changes to the hosted Supabase project by running the following command:

```bash copy
supabase db push
```

#### Setup environment variables

You can find `Project connect details` by clicking **Connect** in the top bar of the dashboard and copy the URI from the `Transaction pooler` section. Remember to replace the password placeholder with your actual database password.

Read more about Connection Pooler in the [documentation](https://supabase.com/docs/guides/database/connecting-to-postgres#connection-pooler).

Update your edge function code to use the `DATABASE_URL` environment variable instead of `SUPABASE_DB_URL`:

```typescript copy filename="supabase/functions/drizzle-tutorial/index.ts"
// imports

// const connectionString = Deno.env.get("SUPABASE_DB_URL")!;
const connectionString = Deno.env.get("DATABASE_URL")!;

// code
```

Run the following command to set the environment variable:

```bash copy
supabase secrets set DATABASE_URL=<CONNECTION_STRING>
```

Learn more about managing environment variables in Supabase Edge Functions in the [documentation](https://supabase.com/docs/guides/functions/secrets).

#### Deploy your function

Deploy your function by running the following command:

```bash copy
supabase functions deploy drizzle-tutorial --no-verify-jwt
```
</Steps>

Finally, you can use URL of the deployed project and navigate to the route you created `(e.g. /drizzle-tutorial)` to access your edge function.


Source: https://orm.drizzle.team/docs/tutorials/drizzle-with-supabase


import Prerequisites from "@mdx/Prerequisites.astro";
import Npm from '@mdx/Npm.astro';
import Steps from '@mdx/Steps.astro';
import Section from "@mdx/Section.astro";
import Callout from '@mdx/Callout.astro';

This tutorial demonstrates how to use Drizzle ORM with [Supabase Database](https://supabase.com/docs/guides/database/overview). Every Supabase project comes with a full [Postgres](https://www.postgresql.org/docs) database.

<Prerequisites>
- You should have installed Drizzle ORM and [Drizzle kit](/docs/kit-overview). You can do this by running the following command:
<Npm>
  drizzle-orm@rc
  -D drizzle-kit@rc
</Npm>
- You should have installed `dotenv` package for managing environment variables. Read more about this package [here](https://www.npmjs.com/package/dotenv)
<Npm>
  dotenv
</Npm>

- You should have installed `postgres` package for connecting to the Postgres database. Read more about this package [here](https://www.npmjs.com/package/postgres)
<Npm>
  postgres
</Npm>

- You should have the latest version of [Supabase CLI](https://supabase.com/docs/guides/cli/getting-started#installing-the-supabase-cli) installed (Only if you want to use the Supabase CLI for migrations)
</Prerequisites>

Check [Supabase documentation](https://supabase.com/docs/guides/database/connecting-to-postgres#connecting-with-drizzle) to learn how to connect to the database with Drizzle ORM.

## Setup Supabase and Drizzle ORM

<Steps>
#### Create a new Supabase project

You can create new Supabase project in the [dashboard](https://supabase.com/dashboard) or by following this [link](https://database.new/).

#### Setup connection string variable

Navigate to [Database Settings](https://supabase.com/dashboard/project/_/settings/database) and copy the URI from the `Connection String` section. Make sure to use `connection pooling`. Remember to replace the password placeholder with your actual database password.

Add `DATABASE_URL` variable to your `.env` or `.env.local` file.

```plaintext copy
DATABASE_URL=<YOUR_DATABASE_URL>
```

Read more about Connection Pooler and pooling modes in the [documentation](https://supabase.com/docs/guides/database/connecting-to-postgres#connection-pooler).

#### Connect Drizzle ORM to your database

Create a `index.ts` file in the `src/db` directory and set up your database configuration:

```typescript copy filename="src/db/index.ts"
import { config } from 'dotenv';
import { drizzle } from 'drizzle-orm/postgres-js';
import postgres from 'postgres';

config({ path: '.env' }); // or .env.local

const client = postgres(process.env.DATABASE_URL!);
export const db = drizzle({ client });
```

#### Create tables

Create a `schema.ts` file in the `src/db` directory and declare your tables:

```typescript copy filename="src/db/schema.ts"
import { integer, pgTable, serial, text, timestamp } from 'drizzle-orm/pg-core';

export const usersTable = pgTable('users_table', {
  id: serial('id').primaryKey(),
  name: text('name').notNull(),
  age: integer('age').notNull(),
  email: text('email').notNull().unique(),
});

export const postsTable = pgTable('posts_table', {
  id: serial('id').primaryKey(),
  title: text('title').notNull(),
  content: text('content').notNull(),
  userId: integer('user_id')
    .notNull()
    .references(() => usersTable.id, { onDelete: 'cascade' }),
  createdAt: timestamp('created_at').notNull().defaultNow(),
  updatedAt: timestamp('updated_at')
    .notNull()
    .$onUpdate(() => new Date()),
});

export type InsertUser = typeof usersTable.$inferInsert;
export type SelectUser = typeof usersTable.$inferSelect;

export type InsertPost = typeof postsTable.$inferInsert;
export type SelectPost = typeof postsTable.$inferSelect;
```

#### Setup Drizzle config file

**Drizzle config** - a configuration file that is used by [Drizzle Kit](/docs/kit-overview) and contains all the information about your database connection, migration folder and schema files.

Create a `drizzle.config.ts` file in the root of your project and add the following content:

```typescript copy filename="drizzle.config.ts"
import { config } from 'dotenv';
import { defineConfig } from 'drizzle-kit';

config({ path: '.env' });

export default defineConfig({
  schema: './src/db/schema.ts',
  out: './supabase/migrations',
  dialect: 'postgresql',
  dbCredentials: {
    url: process.env.DATABASE_URL!,
  },
});
```

#### Applying changes to the database

You can generate migrations using `drizzle-kit generate` command and then run them using the `drizzle-kit migrate` command.

Generate migrations:

```bash copy
npx drizzle-kit generate
```

These migrations are stored in the `supabase/migrations`  directory, as specified in your `drizzle.config.ts`. This directory will contain the SQL files necessary to update your database schema and a `meta` folder for storing snapshots of the schema at different migration stages.

Example of a generated migration:

```sql
CREATE TABLE IF NOT EXISTS "posts_table" (
	"id" serial PRIMARY KEY NOT NULL,
	"title" text NOT NULL,
	"content" text NOT NULL,
	"user_id" integer NOT NULL,
	"created_at" timestamp DEFAULT now() NOT NULL,
	"updated_at" timestamp NOT NULL
);
--> statement-breakpoint
CREATE TABLE IF NOT EXISTS "users_table" (
	"id" serial PRIMARY KEY NOT NULL,
	"name" text NOT NULL,
	"age" integer NOT NULL,
	"email" text NOT NULL,
	CONSTRAINT "users_table_email_unique" UNIQUE("email")
);
--> statement-breakpoint
DO $$ BEGIN
 ALTER TABLE "posts_table" ADD CONSTRAINT "posts_table_user_id_users_table_id_fk" FOREIGN KEY ("user_id") REFERENCES "users_table"("id") ON DELETE cascade ON UPDATE no action;
EXCEPTION
 WHEN duplicate_object THEN null;
END $$;
```

Run migrations:

```bash copy
npx drizzle-kit migrate
```

Learn more about [migration process](/docs/migrations). You can also apply migrations using [Supabase CLI](https://supabase.com/docs/guides/cli/getting-started):
- For tables that already exist, manually review the generated migration files from `npx drizzle-kit generate` and comment out or adjust any unsafe pure create statements (e.g., `CREATE SCHEMA "auth";`) while ensuring safe conditional creates (e.g., `CREATE TABLE IF NOT EXISTS "auth"."users"`) are properly handled.

Alternatively, you can push changes directly to the database using [Drizzle kit push command](/docs/kit-overview#prototyping-with-db-push):

```bash copy
npx drizzle-kit push
```

<Callout type="warning">Push command is good for situations where you need to quickly test new schema designs or changes in a local development environment, allowing for fast iterations without the overhead of managing migration files.</Callout>

To apply migrations using the Supabase CLI you should follow these steps:
 
Generate migrations using Drizzle Kit:

```bash copy
npx drizzle-kit generate
```

Initialize the local Supabase project:

```bash copy
supabase init
```

Link it to your remote project:

```bash copy
supabase link
```

Push changes to the database:

```bash copy
supabase db push
```
</Steps>

## Basic file structure

This is the basic file structure of the project. In the `src/db` directory, we have database-related files including connection in `index.ts` and schema definitions in `schema.ts`.

```plaintext
📦 <project root>
 ├ 📂 src
 │   ├ 📂 db
 │   │  ├ 📜 index.ts
 │   │  └ 📜 schema.ts
 ├ 📂 supabase
 │   ├ 📂 migrations
 │   │  ├ 📂 meta
 │   │  │  ├ 📜 _journal.json
 │   │  │  └ 📜 0000_snapshot.json
 │   │  └ 📜 0000_watery_spencer_smythe.sql
 │   └ 📜 config.toml
 ├ 📜 .env
 ├ 📜 drizzle.config.ts
 ├ 📜 package.json
 └ 📜 tsconfig.json
```

## Query examples

For instance, we create `src/db/queries` folder and separate files for each operation: insert, select, update, delete.

#### Insert data

Read more about insert query in the [documentation](/docs/insert).

```typescript copy filename="src/db/queries/insert.ts" {4, 8}
import { db } from '../index';
import { InsertPost, InsertUser, postsTable, usersTable } from '../schema';

export async function createUser(data: InsertUser) {
  await db.insert(usersTable).values(data);
}

export async function createPost(data: InsertPost) {
  await db.insert(postsTable).values(data);
}
```

#### Select data

Read more about select query in the [documentation](/docs/select).

<Callout type='warning'>
`getColumns` available starting from `drizzle-orm@1.0.0-beta.2`(read more [here](/docs/upgrade-v1))

If you are on pre-1 version(like `0.45.1`) then use `getTableColumns`
</Callout>

```typescript copy filename="src/db/queries/select.ts" {5, 16, 41}
import { asc, between, count, eq, getColumns, sql } from 'drizzle-orm';
import { db } from '../index';
import { SelectUser, postsTable, usersTable } from '../schema';

export async function getUserById(id: SelectUser['id']): Promise<
  Array<{
    id: number;
    name: string;
    age: number;
    email: string;
  }>
> {
  return db.select().from(usersTable).where(eq(usersTable.id, id));
}

export async function getUsersWithPostsCount(
  page = 1,
  pageSize = 5,
): Promise<
  Array<{
    postsCount: number;
    id: number;
    name: string;
    age: number;
    email: string;
  }>
> {
  return db
    .select({
      ...getColumns(usersTable),
      postsCount: count(postsTable.id),
    })
    .from(usersTable)
    .leftJoin(postsTable, eq(usersTable.id, postsTable.userId))
    .groupBy(usersTable.id)
    .orderBy(asc(usersTable.id))
    .limit(pageSize)
    .offset((page - 1) * pageSize);
}

export async function getPostsForLast24Hours(
  page = 1,
  pageSize = 5,
): Promise<
  Array<{
    id: number;
    title: string;
  }>
> {
  return db
    .select({
      id: postsTable.id,
      title: postsTable.title,
    })
    .from(postsTable)
    .where(between(postsTable.createdAt, sql`now() - interval '1 day'`, sql`now()`))
    .orderBy(asc(postsTable.title), asc(postsTable.id))
    .limit(pageSize)
    .offset((page - 1) * pageSize);
}
```

Alternatively, you can use [relational query syntax](/docs/rqb).
#### Update data

Read more about update query in the [documentation](/docs/update).

```typescript copy filename="src/db/queries/update.ts" {5}
import { eq } from 'drizzle-orm';
import { db } from '../index';
import { SelectPost, postsTable } from '../schema';

export async function updatePost(id: SelectPost['id'], data: Partial<Omit<SelectPost, 'id'>>) {
  await db.update(postsTable).set(data).where(eq(postsTable.id, id));
}
```

#### Delete data

Read more about delete query in the [documentation](/docs/delete).

```typescript copy filename="src/db/queries/delete.ts" {5}
import { eq } from 'drizzle-orm';
import { db } from '../index';
import { SelectUser, usersTable } from '../schema';

export async function deleteUser(id: SelectUser['id']) {
  await db.delete(usersTable).where(eq(usersTable.id, id));
}
```


Source: https://orm.drizzle.team/docs/tutorials/drizzle-with-turso


import Prerequisites from "@mdx/Prerequisites.astro";
import Npm from '@mdx/Npm.astro';
import Steps from '@mdx/Steps.astro';
import Section from "@mdx/Section.astro";
import Callout from '@mdx/Callout.astro';

This tutorial demonstrates how to use Drizzle ORM with [Turso](https://docs.turso.tech/introduction).

<Prerequisites>
- You should have installed Drizzle ORM and [Drizzle kit](/docs/kit-overview). You can do this by running the following command:
<Npm>
  drizzle-orm@rc
  -D drizzle-kit@rc
</Npm>
- You should have installed `dotenv` package for managing environment variables. Read more about this package [here](https://www.npmjs.com/package/dotenv)
<Npm>
  dotenv
</Npm>
- You should have installed `@libsql/client` package. Read more about this package [here](https://www.npmjs.com/package/@libsql/client).
<Npm>
  @libsql/client
</Npm>
- You should have installed Turso CLI. Check [documentation](https://docs.turso.tech/cli/introduction) for more information
</Prerequisites>

[Turso](https://docs.turso.tech/concepts) is a SQLite-compatible database built on [libSQL](https://docs.turso.tech/libsql), the Open Contribution fork of SQLite. It enables scaling to hundreds of thousands of databases per organization and supports replication to any location, including your own servers, for microsecond-latency access. You can read more about Turso’s concepts [here](https://docs.turso.tech/concepts).

Drizzle ORM natively supports libSQL driver.
We embrace SQL dialects and dialect specific drivers and syntax and mirror most popular SQLite-like `all`, `get`, `values` and `run` query methods syntax.

Check [official documentation](https://docs.turso.tech/quickstart) to setup Turso database.

## Setup Turso and Drizzle ORM

<Steps>
#### Signup or login to Turso

Signup:

```bash copy
turso auth signup
```

Login:

```bash copy
turso auth login
```

#### Create new database

Create new database by running the `turso db create <DATABASE_NAME>` command:

```bash copy
turso db create drizzle-turso-db
```

To see information about the database, run the following command:

```bash copy
turso db show drizzle-turso-db
```

#### Create an authentication token

To create an authentication token for your database, run the following command:

```bash copy
turso db tokens create drizzle-turso-db
```

Learn more about this command and its options in the [documentation](https://docs.turso.tech/cli/db/tokens/create).

#### Update environment variables

Update your `.env` or `.env.local` file with connection url and authentication token.

```text copy
TURSO_CONNECTION_URL=
TURSO_AUTH_TOKEN=
```

#### Connect Drizzle ORM to your database

Create a `index.ts` file in the `src/db` directory and set up your database configuration:

```typescript copy filename="src/db/index.ts"
import { config } from 'dotenv';
import { drizzle } from 'drizzle-orm/libsql';

config({ path: '.env' }); // or .env.local

export const db = drizzle({ connection: {
  url: process.env.TURSO_CONNECTION_URL!,
  authToken: process.env.TURSO_AUTH_TOKEN!,
}});
```

#### Create tables

Create a `schema.ts` file in the `src/db` directory and declare your tables:

```typescript copy filename="src/db/schema.ts"
import { sql } from 'drizzle-orm';
import { integer, sqliteTable, text } from 'drizzle-orm/sqlite-core';

export const usersTable = sqliteTable('users', {
  id: integer('id').primaryKey(),
  name: text('name').notNull(),
  age: integer('age').notNull(),
  email: text('email').unique().notNull(),
});

export const postsTable = sqliteTable('posts', {
  id: integer('id').primaryKey(),
  title: text('title').notNull(),
  content: text('content').notNull(),
  userId: integer('user_id')
    .notNull()
    .references(() => usersTable.id, { onDelete: 'cascade' }),
  createdAt: text('created_at')
    .default(sql`(CURRENT_TIMESTAMP)`)
    .notNull(),
  updatedAt: integer('updated_at', { mode: 'timestamp' }).$onUpdate(() => new Date()),
});

export type InsertUser = typeof usersTable.$inferInsert;
export type SelectUser = typeof usersTable.$inferSelect;

export type InsertPost = typeof postsTable.$inferInsert;
export type SelectPost = typeof postsTable.$inferSelect;
```

#### Setup Drizzle config file

**Drizzle config** - a configuration file that is used by [Drizzle Kit](/docs/kit-overview) and contains all the information about your database connection, migration folder and schema files.

Create a `drizzle.config.ts` file in the root of your project and add the following content:

```typescript copy filename="drizzle.config.ts"
import { config } from 'dotenv';
import { defineConfig } from 'drizzle-kit';

config({ path: '.env' });

export default defineConfig({
  schema: './src/db/schema.ts',
  out: './migrations',
  dialect: 'turso',
  dbCredentials: {
    url: process.env.TURSO_CONNECTION_URL!,
    authToken: process.env.TURSO_AUTH_TOKEN!,
  },
});
```

#### Applying changes to the database

You can generate migrations using `drizzle-kit generate` command and then run them using the `drizzle-kit migrate` command.

Generate migrations:

```bash copy
npx drizzle-kit generate
```

These migrations are stored in the `migrations`  directory, as specified in your `drizzle.config.ts`. This directory will contain the SQL files necessary to update your database schema and a `meta` folder for storing snapshots of the schema at different migration stages.

Example of a generated migration:

```sql
CREATE TABLE `posts` (
	`id` integer PRIMARY KEY NOT NULL,
	`title` text NOT NULL,
	`content` text NOT NULL,
	`user_id` integer NOT NULL,
	`created_at` text DEFAULT (CURRENT_TIMESTAMP) NOT NULL,
	`updated_at` integer,
	FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON UPDATE no action ON DELETE cascade
);
--> statement-breakpoint
CREATE TABLE `users` (
	`id` integer PRIMARY KEY NOT NULL,
	`name` text NOT NULL,
	`age` integer NOT NULL,
	`email` text NOT NULL
);
--> statement-breakpoint
CREATE UNIQUE INDEX `users_email_unique` ON `users` (`email`);
```

Run migrations:

```bash copy
npx drizzle-kit migrate
```

Alternatively, you can push changes directly to the database using [Drizzle kit push command](/docs/kit-overview#prototyping-with-db-push):

```bash copy
npx drizzle-kit push
```

<Callout type="warning">Push command is good for situations where you need to quickly test new schema designs or changes in a local development environment, allowing for fast iterations without the overhead of managing migration files.</Callout>
</Steps>

### Basic file structure

This is the basic file structure of the project. In the `src/db` directory, we have database-related files including connection in `index.ts` and schema definitions in `schema.ts`.

```plaintext
📦 <project root>
 ├ 📂 src
 │   ├ 📂 db
 │   │  ├ 📜 index.ts
 │   │  └ 📜 schema.ts
 ├ 📂 migrations
 │  ├ 📂 meta
 │  │  ├ 📜 _journal.json
 │  │  └ 📜 0000_snapshot.json
 │  └ 📜 0000_watery_spencer_smythe.sql
 ├ 📜 .env
 ├ 📜 drizzle.config.ts
 ├ 📜 package.json
 └ 📜 tsconfig.json
```

## Query examples

For instance, we create `src/db/queries` folder and separate files for each operation: insert, select, update, delete.

#### Insert data

Read more about insert query in the [documentation](/docs/insert).

```typescript copy filename="src/db/queries/insert.ts" {4, 8}
import { db } from '../index';
import { InsertPost, InsertUser, postsTable, usersTable } from '../schema';

export async function createUser(data: InsertUser) {
  await db.insert(usersTable).values(data);
}

export async function createPost(data: InsertPost) {
  await db.insert(postsTable).values(data);
}
```

#### Select data

Read more about select query in the [documentation](/docs/select).

<Callout type='warning'>
`getColumns` available starting from `drizzle-orm@1.0.0-beta.2`(read more [here](/docs/upgrade-v1))

If you are on pre-1 version(like `0.45.1`) then use `getTableColumns`
</Callout>

```typescript copy filename="src/db/queries/select.ts" {5, 16, 41}
import { asc, count, eq, getColumns, gt, sql } from 'drizzle-orm';
import { db } from '../index';
import { SelectUser, postsTable, usersTable } from '../schema';

export async function getUserById(id: SelectUser['id']): Promise<
  Array<{
    id: number;
    name: string;
    age: number;
    email: string;
  }>
> {
  return db.select().from(usersTable).where(eq(usersTable.id, id));
}

export async function getUsersWithPostsCount(
  page = 1,
  pageSize = 5,
): Promise<
  Array<{
    postsCount: number;
    id: number;
    name: string;
    age: number;
    email: string;
  }>
> {
  return db
    .select({
      ...getColumns(usersTable),
      postsCount: count(postsTable.id),
    })
    .from(usersTable)
    .leftJoin(postsTable, eq(usersTable.id, postsTable.userId))
    .groupBy(usersTable.id)
    .orderBy(asc(usersTable.id))
    .limit(pageSize)
    .offset((page - 1) * pageSize);
}

export async function getPostsForLast24Hours(
  page = 1,
  pageSize = 5,
): Promise<
  Array<{
    id: number;
    title: string;
  }>
> {
  return db
    .select({
      id: postsTable.id,
      title: postsTable.title,
    })
    .from(postsTable)
    .where(gt(postsTable.createdAt, sql`(datetime('now','-24 hour'))`))
    .orderBy(asc(postsTable.title), asc(postsTable.id))
    .limit(pageSize)
    .offset((page - 1) * pageSize);
}
```

Alternatively, you can use [relational query syntax](/docs/rqb).

#### Update data

Read more about update query in the [documentation](/docs/update).

```typescript copy filename="src/db/queries/update.ts" {5}
import { eq } from 'drizzle-orm';
import { db } from '../index';
import { SelectPost, postsTable } from '../schema';

export async function updatePost(id: SelectPost['id'], data: Partial<Omit<SelectPost, 'id'>>) {
  await db.update(postsTable).set(data).where(eq(postsTable.id, id));
}
```

#### Delete data

Read more about delete query in the [documentation](/docs/delete).

```typescript copy filename="src/db/queries/delete.ts" {5}
import { eq } from 'drizzle-orm';
import { db } from '../index';
import { SelectUser, usersTable } from '../schema';

export async function deleteUser(id: SelectUser['id']) {
  await db.delete(usersTable).where(eq(usersTable.id, id));
}
```


Source: https://orm.drizzle.team/docs/tutorials/drizzle-with-vercel-edge-functions


import Prerequisites from "@mdx/Prerequisites.astro";
import Npm from '@mdx/Npm.astro';
import Steps from '@mdx/Steps.astro';
import Section from "@mdx/Section.astro";
import Callout from "@mdx/Callout.astro";

This tutorial demonstrates how to use Drizzle ORM with [Vercel Functions](https://vercel.com/docs/functions) in [Edge runtime](https://vercel.com/docs/functions/runtimes/edge-runtime).

<Prerequisites>
- You should have the latest version of [Vercel CLI](https://vercel.com/docs/cli#) installed.
<Npm>
-g vercel
</Npm>

- You should have an existing Next.js project or create a new one using the following command:

```bash copy
npx create-next-app@latest --typescript
```
- You should have installed Drizzle ORM and [Drizzle kit](/docs/kit-overview). You can do this by running the following command:
<Npm>
  drizzle-orm@rc
  -D drizzle-kit@rc
</Npm>
</Prerequisites>

<Callout type="warning">
In case you face the issue with resolving dependencies during installation:

If you're not using React Native, forcing the installation with `--force` or `--legacy-peer-deps` should resolve the issue. If you are using React Native, then you need to use the exact version of React which is compatible with your React Native version.
</Callout>

## Edge-compatible driver

When using Drizzle ORM with Vercel Edge functions you have to use edge-compatible drivers because the functions run in [Edge runtime](https://vercel.com/docs/functions/runtimes/edge-runtime) not in Node.js runtime, so there are some limitations of standard Node.js APIs.

You can choose one of these drivers according to your database dialect:

- [Neon serverless driver](/docs/get-started-postgresql#neon) allows you to query your Neon Postgres databases from serverless and edge environments over HTTP or WebSockets in place of TCP. We recommend using this driver for connecting to `Neon Postgres`.
- [Vercel Postgres driver](/docs/get-started-postgresql#vercel-postgres) is built on top of the `Neon serverless driver`. We recommend using this driver for connecting to `Vercel Postgres`.
- [PlanetScale serverless driver](/docs/mysql/get-started-mysql#planetscale) allows you access any `MySQL` client and execute queries over an HTTP connection, which is generally not blocked by cloud providers.
- [libSQL client](/docs/sqlite/get-started-sqlite#turso) allows you to access [Turso](https://docs.turso.tech/introduction) database.

## Navigation

- Navigate directly to the [Neon Postgres](/docs/tutorials/drizzle-with-vercel-edge-functions#neon-postgres) section.
- Navigate directly to the [Vercel Postgres](/docs/tutorials/drizzle-with-vercel-edge-functions#vercel-postgres) section.
- Navigate directly to the [PlanetScale](/docs/tutorials/drizzle-with-vercel-edge-functions#planetscale) section.
- Navigate directly to the [Turso](/docs/tutorials/drizzle-with-vercel-edge-functions#turso) section.

### Neon Postgres

<Steps>
#### Install the `@neondatabase/serverless` driver

Install the `@neondatabase/serverless` driver:

<Npm>
@neondatabase/serverless
</Npm>

#### Create a table

Create a `schema.ts` file in the `src/db` directory and declare a table schema:

```typescript copy filename="src/db/schema.ts"
import { pgTable, serial, text } from "drizzle-orm/pg-core";

export const usersTable = pgTable('users_table', {
  id: serial('id').primaryKey(),
  name: text('name').notNull(),
  age: text('age').notNull(),
  email: text('email').notNull().unique(),
})
```

#### Setup Drizzle config file

**Drizzle config** - a configuration file that is used by [Drizzle Kit](/docs/kit-overview) and contains all the information about your database connection, migration folder and schema files.

Create a `drizzle.config.ts` file in the root of your project and add the following content:

```typescript copy filename="drizzle.config.ts"
import { defineConfig } from "drizzle-kit";

export default defineConfig({
  schema: "./src/db/schema.ts",
  dialect: "postgresql",
  dbCredentials: {
    url: process.env.POSTGRES_URL!,
  },
});
```

Configure your database connection string in the `.env` file:

```plaintext filename=".env"
POSTGRES_URL="postgres://[user]:[password]@[host]-[region].aws.neon.tech:5432/[db-name]?sslmode=[ssl-mode]"
```

#### Applying changes to the database

You can generate migrations using `drizzle-kit generate` command and then run them using the `drizzle-kit migrate` command.

Generate migrations:

```bash copy
npx drizzle-kit generate
```

These migrations are stored in the `drizzle` directory, as specified in your `drizzle.config.ts`. This directory will contain the SQL files necessary to update your database schema and a `meta` folder for storing snapshots of the schema at different migration stages.

Example of a generated migration:

```sql
CREATE TABLE IF NOT EXISTS "users_table" (
	"id" serial PRIMARY KEY NOT NULL,
	"name" text NOT NULL,
	"age" text NOT NULL,
	"email" text NOT NULL,
	CONSTRAINT "users_table_email_unique" UNIQUE("email")
);
```

Run migrations:

```bash copy
npx drizzle-kit migrate
```

Alternatively, you can push changes directly to the database using [Drizzle kit push command](/docs/kit-overview#prototyping-with-db-push):

```bash copy
npx drizzle-kit push
```

<Callout type="warning">Push command is good for situations where you need to quickly test new schema designs or changes in a local development environment, allowing for fast iterations without the overhead of managing migration files.</Callout>

#### Connect Drizzle ORM to your database

Create a `index.ts` file in the `src/db` directory and set up your database configuration:

```typescript copy filename="src/db/index.ts"
import { drizzle } from 'drizzle-orm/neon-serverless';


export const db = drizzle(process.env.POSTGRES_URL!)
```

#### Create an API route

Create `route.ts` file in `src/app/api/hello` directory. To learn more about how to write a function, see the [Functions API Reference](https://vercel.com/docs/functions/functions-api-reference) and [Vercel Functions Quickstart](https://vercel.com/docs/functions/quickstart).

```ts copy filename="src/app/api/hello/route.ts"
import { db } from "@/db";
import { usersTable } from "@/db/schema";
import { NextResponse } from "next/server";

export const dynamic = 'force-dynamic'; // static by default, unless reading the request
export const runtime = 'edge' // specify the runtime to be edge

export async function GET(request: Request) {
  const users = await db.select().from(usersTable)

  return NextResponse.json({ users, message: 'success' });
}
```

#### Test your code locally

Run the `next dev` command to start your local development server:

```bash copy
npx next dev
```

Navigate to the route you created `(e.g. /api/hello)` in your browser:

```plaintext
{
  "users": [],
  "message": "success"
}
```

#### Deploy your project

Create a new project in the [dashboard](https://vercel.com/new) or run the `vercel` command to deploy your project:

```bash copy
vercel
```

Add `POSTGRES_URL` environment variable:

```bash copy
vercel env add POSTGRES_URL
```

Redeploy your project to update your environment variables:

```bash copy
vercel
```
</Steps>

Finally, you can use URL of the deployed project and navigate to the route you created `(e.g. /api/hello)` to access your edge function.

### Vercel Postgres

You can check quickstart guide for Drizzle with Vercel Postgres client in the [documentation](/docs/get-started-postgresql#vercel-postgres).

<Steps>
#### Install the `@vercel/postgres` driver

Install the `@vercel/postgres` driver:

<Npm>
@vercel/postgres
</Npm>

#### Create a table

Create a `schema.ts` file in the `src/db` directory and declare a table schema:

```typescript copy filename="src/db/schema.ts"
import { pgTable, serial, text } from "drizzle-orm/pg-core";

export const usersTable = pgTable('users_table', {
  id: serial('id').primaryKey(),
  name: text('name').notNull(),
  age: text('age').notNull(),
  email: text('email').notNull().unique(),
})
```

#### Setup Drizzle config file

**Drizzle config** - a configuration file that is used by [Drizzle Kit](/docs/kit-overview) and contains all the information about your database connection, migration folder and schema files.

Create a `drizzle.config.ts` file in the root of your project and add the following content:

```typescript copy filename="drizzle.config.ts"
import { defineConfig } from "drizzle-kit";

export default defineConfig({
  schema: "./src/db/schema.ts",
  dialect: "postgresql",
  dbCredentials: {
    url: process.env.POSTGRES_URL!,
  },
});
```

Configure your database connection string in the `.env` file:

```plaintext filename=".env"
POSTGRES_URL="postgres://[user]:[password]@[host]-[region].aws.neon.tech:5432/[db-name]?sslmode=[ssl-mode]"
```

#### Applying changes to the database

You can generate migrations using `drizzle-kit generate` command and then run them using the `drizzle-kit migrate` command.

Generate migrations:

```bash copy
npx drizzle-kit generate
```

These migrations are stored in the `drizzle` directory, as specified in your `drizzle.config.ts`. This directory will contain the SQL files necessary to update your database schema and a `meta` folder for storing snapshots of the schema at different migration stages.

Example of a generated migration:

```sql
CREATE TABLE IF NOT EXISTS "users_table" (
	"id" serial PRIMARY KEY NOT NULL,
	"name" text NOT NULL,
	"age" text NOT NULL,
	"email" text NOT NULL,
	CONSTRAINT "users_table_email_unique" UNIQUE("email")
);
```

Run migrations:

```bash copy
npx drizzle-kit migrate
```

Alternatively, you can push changes directly to the database using [Drizzle kit push command](/docs/kit-overview#prototyping-with-db-push):

```bash copy
npx drizzle-kit push
```

<Callout type="warning">Push command is good for situations where you need to quickly test new schema designs or changes in a local development environment, allowing for fast iterations without the overhead of managing migration files.</Callout>

#### Connect Drizzle ORM to your database

Create a `index.ts` file in the `src/db` directory and set up your database configuration:

```typescript copy filename="src/db/index.ts"
import { drizzle } from 'drizzle-orm/vercel-postgres';

export const db = drizzle()
```

#### Create an API route

Create `route.ts` in `src/app/api/hello` directory. To learn more about how to write a function, see the [Functions API Reference](https://vercel.com/docs/functions/functions-api-reference) and [Vercel Functions Quickstart](https://vercel.com/docs/functions/quickstart).

```ts copy filename="src/app/api/hello/route.ts"

import { db } from "@/db";
import { usersTable } from "@/db/schema";
import { NextResponse } from "next/server";

export const dynamic = 'force-dynamic'; // static by default, unless reading the request
export const runtime = 'edge' // specify the runtime to be edge

export async function GET(request: Request) {
  const users = await db.select().from(usersTable)

  return NextResponse.json({ users, message: 'success' });
}
```

#### Test your code locally

Run the `next dev` command to start your local development server:

```bash copy
npx next dev
```

Navigate to the route you created `(e.g. /api/hello)` in your browser:

```plaintext
{
  "users": [],
  "message": "success"
}
```

#### Deploy your project

Create a new project in the [dashboard](https://vercel.com/new) or run the `vercel` command to deploy your project:

```bash copy
vercel
```

Add `POSTGRES_URL` environment variable:

```bash copy
vercel env add POSTGRES_URL
```

Redeploy your project to update your environment variables:

```bash copy
vercel
```
</Steps>

Finally, you can use URL of the deployed project and navigate to the route you created `(e.g. /api/hello)` to access your edge function.

### PlanetScale

In this tutorial we use [PlanetScale MySQL](https://planetscale.com).

<Steps>
#### Install the `@planetscale/database` driver

Install the `@planetscale/database` driver:

<Npm>
@planetscale/database
</Npm>

#### Create a table

Create a `schema.ts` file in the `src/db` directory and declare a table schema:

```typescript copy filename="src/db/schema.ts"
import { mysqlTable, serial, text } from "drizzle-orm/mysql-core";

export const usersTable = mysqlTable('users_table', {
  id: serial('id').primaryKey(),
  name: text('name').notNull(),
  age: text('age').notNull(),
  email: text('email').notNull().unique(),
})
```

#### Setup Drizzle config file

**Drizzle config** - a configuration file that is used by [Drizzle Kit](/docs/kit-overview) and contains all the information about your database connection, migration folder and schema files.

Create a `drizzle.config.ts` file in the root of your project and add the following content:

```typescript copy filename="drizzle.config.ts"
import { defineConfig } from "drizzle-kit";

export default defineConfig({
  schema: "./src/db/schema.ts",
  dialect: "mysql",
  dbCredentials: {
    url: process.env.MYSQL_URL!,
  },
});
```

Configure your database connection string in the `.env` file:

```plaintext filename=".env"
MYSQL_URL="mysql://[user]:[password]@[host].[region].psdb.cloud/[db-name]?ssl={'rejectUnauthorized':[ssl-rejectUnauthorized]}"
```

#### Applying changes to the database

You can generate migrations using `drizzle-kit generate` command and then run them using the `drizzle-kit migrate` command.

Generate migrations:

```bash copy
npx drizzle-kit generate
```

These migrations are stored in the `drizzle` directory, as specified in your `drizzle.config.ts`. This directory will contain the SQL files necessary to update your database schema and a `meta` folder for storing snapshots of the schema at different migration stages.

Example of a generated migration:

```sql
CREATE TABLE `users_table` (
	`id` serial AUTO_INCREMENT NOT NULL,
	`name` text NOT NULL,
	`age` text NOT NULL,
	`email` text NOT NULL,
	CONSTRAINT `users_table_id` PRIMARY KEY(`id`),
	CONSTRAINT `users_table_email_unique` UNIQUE(`email`)
);
```

Run migrations:

```bash copy
npx drizzle-kit migrate
```

Alternatively, you can push changes directly to the database using [Drizzle kit push command](/docs/kit-overview#prototyping-with-db-push):

```bash copy
npx drizzle-kit push
```

<Callout type="warning">Push command is good for situations where you need to quickly test new schema designs or changes in a local development environment, allowing for fast iterations without the overhead of managing migration files.</Callout>

#### Connect Drizzle ORM to your database

Create a `index.ts` file in the `src/db` directory and set up your database configuration:

```typescript copy filename="src/db/index.ts"
import { drizzle } from "drizzle-orm/planetscale-serverless";

export const db = drizzle(process.env.MYSQL_URL!)
```

#### Create an API route

Create `route.ts` in `src/app/api/hello` directory. To learn more about how to write a function, see the [Functions API Reference](https://vercel.com/docs/functions/functions-api-reference) and [Vercel Functions Quickstart](https://vercel.com/docs/functions/quickstart).

```ts copy filename="src/app/api/hello/route.ts"
import { db } from "@/app/db/db";
import { usersTable } from "@/app/db/schema";
import { NextResponse } from "next/server";

export const dynamic = 'force-dynamic'; // static by default, unless reading the request
export const runtime = 'edge' // specify the runtime to be edge

export async function GET(request: Request) {
  const users = await db.select().from(usersTable)

  return NextResponse.json({ users, message: 'success' });
}
```

#### Test your code locally

Run the `next dev` command to start your local development server:

```bash copy
npx next dev
```

Navigate to the route you created `(e.g. /api/hello)` in your browser:

```plaintext
{
  "users": [],
  "message": "success"
}
```

#### Deploy your project

Create a new project in the [dashboard](https://vercel.com/new) or run the `vercel` command to deploy your project:

```bash copy
vercel
```

Add `MYSQL_URL` environment variable:

```bash copy
vercel env add MYSQL_URL
```

Redeploy your project to update your environment variables:

```bash copy
vercel
```
</Steps>

Finally, you can use URL of the deployed project and navigate to the route you created `(e.g. /api/hello)` to access your edge function.

### Turso

You can check [quickstart guide](/docs/sqlite/get-started-sqlite#turso) or [tutorial](/docs/tutorials/drizzle-with-turso) for Drizzle with Turso in the documentation.

<Steps>
#### Install the `@libsql/client` driver

Install the `@libsql/client` driver:

<Npm>
@libsql/client
</Npm>

#### Create a table

Create a `schema.ts` file in the `src/db` directory and declare a table schema:

```typescript copy filename="src/db/schema.ts"
import { integer, sqliteTable, text } from "drizzle-orm/sqlite-core";

export const usersTable = sqliteTable('users_table', {
  id: integer('id').primaryKey(),
  name: text('name').notNull(),
  age: text('age').notNull(),
  email: text('email').notNull().unique(),
})
```

#### Setup Drizzle config file

**Drizzle config** - a configuration file that is used by [Drizzle Kit](/docs/kit-overview) and contains all the information about your database connection, migration folder and schema files.

Create a `drizzle.config.ts` file in the root of your project and add the following content:

```typescript copy filename="drizzle.config.ts"
import { defineConfig } from "drizzle-kit";

export default defineConfig({
  schema: "./src/db/schema.ts",
  dialect: "turso",
  dbCredentials: {
    url: process.env.TURSO_CONNECTION_URL!,
    authToken: process.env.TURSO_AUTH_TOKEN!,
  },
});
```

Configure your database connection string and auth token in the `.env` file:

```plaintext filename=".env"
TURSO_CONNECTION_URL="libsql://[db-name].turso.io"
TURSO_AUTH_TOKEN="[auth-token]"
```

#### Applying changes to the database

You can generate migrations using `drizzle-kit generate` command and then run them using the `drizzle-kit migrate` command.

Generate migrations:

```bash copy
npx drizzle-kit generate
```

These migrations are stored in the `drizzle` directory, as specified in your `drizzle.config.ts`. This directory will contain the SQL files necessary to update your database schema and a `meta` folder for storing snapshots of the schema at different migration stages.

Example of a generated migration:

```sql
CREATE TABLE `users_table` (
	`id` integer PRIMARY KEY NOT NULL,
	`name` text NOT NULL,
	`age` text NOT NULL,
	`email` text NOT NULL
);
--> statement-breakpoint
CREATE UNIQUE INDEX `users_table_email_unique` ON `users_table` (`email`);
```

Run migrations:

```bash copy
npx drizzle-kit migrate
```

Alternatively, you can push changes directly to the database using [Drizzle kit push command](/docs/kit-overview#prototyping-with-db-push):

```bash copy
npx drizzle-kit push
```

<Callout type="warning">Push command is good for situations where you need to quickly test new schema designs or changes in a local development environment, allowing for fast iterations without the overhead of managing migration files.</Callout>

#### Connect Drizzle ORM to your database

Create a `index.ts` file in the `src/db` directory and set up your database configuration:

```typescript copy filename="src/db/index.ts"
import { drizzle } from 'drizzle-orm/libsql';

export const db = drizzle({ connection: {
  url: process.env.TURSO_CONNECTION_URL!,
  authToken: process.env.TURSO_AUTH_TOKEN!,
}})
```

#### Create an API route

Create `route.ts` in `src/app/api/hello` directory. To learn more about how to write a function, see the [Functions API Reference](https://vercel.com/docs/functions/functions-api-reference) and [Vercel Functions Quickstart](https://vercel.com/docs/functions/quickstart).

```ts copy filename="src/app/api/hello/route.ts"
import { db } from "@/app/db/db";
import { usersTable } from "@/app/db/schema";
import { NextResponse } from "next/server";

export const dynamic = 'force-dynamic'; // static by default, unless reading the request
export const runtime = 'edge' // specify the runtime to be edge

export async function GET(request: Request) {
  const users = await db.select().from(usersTable)

  return NextResponse.json({ users, message: 'success' });
}
```

#### Test your code locally

Run the `next dev` command to start your local development server:

```bash copy
npx next dev
```

Navigate to the route you created `(e.g. /api/hello)` in your browser:

```plaintext
{
  "users": [],
  "message": "success"
}
```

#### Deploy your project

Create a new project in the [dashboard](https://vercel.com/new) or run the `vercel` command to deploy your project:

```bash copy
vercel
```

Add `TURSO_CONNECTION_URL` environment variable:

```bash copy
vercel env add TURSO_CONNECTION_URL
```

Add `TURSO_AUTH_TOKEN` environment variable:

```bash copy
vercel env add TURSO_AUTH_TOKEN
```

Redeploy your project to update your environment variables:

```bash copy
vercel
```
</Steps>

Finally, you can use URL of the deployed project and navigate to the route you created `(e.g. /api/hello)` to access your edge function.


Source: https://orm.drizzle.team/docs/tutorials/drizzle-with-vercel


import Prerequisites from "@mdx/Prerequisites.astro";
import Npm from '@mdx/Npm.astro';
import Steps from '@mdx/Steps.astro';
import Section from "@mdx/Section.astro";
import Callout from '@mdx/Callout.astro';

This tutorial demonstrates how to use Drizzle ORM with [Vercel Postgres](https://vercel.com/docs/storage/vercel-postgres). Vercel Postgres is a serverless SQL database designed to integrate with Vercel Functions and your frontend framework.

<Prerequisites>
- You should have installed Drizzle ORM and [Drizzle kit](/docs/kit-overview). You can do this by running the following command:
<Npm>
  drizzle-orm@rc
  -D drizzle-kit@rc
</Npm>

- You should have installed `dotenv` package for managing environment variables. Read more about this package [here](https://www.npmjs.com/package/dotenv)
<Npm>
  dotenv
</Npm>

- You should have installed `@vercel/postgres` package. Read more about this package [here](https://www.npmjs.com/package/@vercel/postgres)
<Npm>
  @vercel/postgres
</Npm>  
</Prerequisites>

Check [Vercel documentation](https://vercel.com/docs/storage/vercel-postgres/using-an-orm#drizzle) to learn how to connect to the database with Drizzle ORM.

## Setup Vercel Postgres and Drizzle ORM

<Steps>
#### Create a new Vercel Postgres database

You can create new Vercel Postgres database in the [dashboard](https://vercel.com/dashboard).

Read Vercel Postgres [documentation](https://vercel.com/docs/storage/vercel-postgres/quickstart) to learn how to create a new database.

#### Setup connection string variable

Navigate to your Vercel Postgres database and copy `POSTGRES_URL` from `.env.local` section.

Add `POSTGRES_URL` to your `.env.local` or `.env` file.

```plaintext copy
POSTGRES_URL=<YOUR_DATABASE_URL>
```

#### Connect Drizzle ORM to your database

Create a `index.ts` file in the `src/db` directory and set up your database configuration:

```typescript copy filename="src/db/index.ts"
import { drizzle } from 'drizzle-orm/vercel-postgres';
import { config } from 'dotenv';

config({ path: '.env.local' }); // or .env

export const db = drizzle();

```

#### Create tables

Create a `schema.ts` file in the `src/db` directory and declare your tables:

```typescript copy filename="src/db/schema.ts"
import { integer, pgTable, serial, text, timestamp } from 'drizzle-orm/pg-core';

export const usersTable = pgTable('users_table', {
  id: serial('id').primaryKey(),
  name: text('name').notNull(),
  age: integer('age').notNull(),
  email: text('email').notNull().unique(),
});

export const postsTable = pgTable('posts_table', {
  id: serial('id').primaryKey(),
  title: text('title').notNull(),
  content: text('content').notNull(),
  userId: integer('user_id')
    .notNull()
    .references(() => usersTable.id, { onDelete: 'cascade' }),
  createdAt: timestamp('created_at').notNull().defaultNow(),
  updatedAt: timestamp('updated_at')
    .notNull()
    .$onUpdate(() => new Date()),
});

export type InsertUser = typeof usersTable.$inferInsert;
export type SelectUser = typeof usersTable.$inferSelect;

export type InsertPost = typeof postsTable.$inferInsert;
export type SelectPost = typeof postsTable.$inferSelect;
```

#### Setup Drizzle config file

**Drizzle config** - a configuration file that is used by [Drizzle Kit](/docs/kit-overview) and contains all the information about your database connection, migration folder and schema files.

Create a `drizzle.config.ts` file in the root of your project and add the following content:

```typescript copy filename="drizzle.config.ts"
import { config } from 'dotenv';
import { defineConfig } from 'drizzle-kit';

config({ path: '.env.local' });

export default defineConfig({
  schema: './src/db/schema.ts',
  out: './migrations',
  dialect: 'postgresql',
  dbCredentials: {
    url: process.env.POSTGRES_URL!,
  },
});
```

#### Applying changes to the database

You can generate migrations using `drizzle-kit generate` command and then run them using the `drizzle-kit migrate` command.

Generate migrations:

```bash copy
npx drizzle-kit generate
```

These migrations are stored in the `drizzle/migrations`  directory, as specified in your `drizzle.config.ts`. This directory will contain the SQL files necessary to update your database schema and a `meta` folder for storing snapshots of the schema at different migration stages.

Example of a generated migration:

```sql
CREATE TABLE IF NOT EXISTS "posts_table" (
	"id" serial PRIMARY KEY NOT NULL,
	"title" text NOT NULL,
	"content" text NOT NULL,
	"user_id" integer NOT NULL,
	"created_at" timestamp DEFAULT now() NOT NULL,
	"updated_at" timestamp NOT NULL
);
--> statement-breakpoint
CREATE TABLE IF NOT EXISTS "users_table" (
	"id" serial PRIMARY KEY NOT NULL,
	"name" text NOT NULL,
	"age" integer NOT NULL,
	"email" text NOT NULL,
	CONSTRAINT "users_table_email_unique" UNIQUE("email")
);
--> statement-breakpoint
DO $$ BEGIN
 ALTER TABLE "posts_table" ADD CONSTRAINT "posts_table_user_id_users_table_id_fk" FOREIGN KEY ("user_id") REFERENCES "users_table"("id") ON DELETE cascade ON UPDATE no action;
EXCEPTION
 WHEN duplicate_object THEN null;
END $$;
```

Run migrations:

```bash copy
npx drizzle-kit migrate
```

Alternatively, you can push changes directly to the database using [Drizzle kit push command](/docs/kit-overview#prototyping-with-db-push):

```bash copy
npx drizzle-kit push
```

<Callout type="warning">Push command is good for situations where you need to quickly test new schema designs or changes in a local development environment, allowing for fast iterations without the overhead of managing migration files.</Callout>

</Steps>

## Basic file structure

This is the basic file structure of the project. In the `src/db` directory, we have database-related files including connection in `index.ts` and schema definitions in `schema.ts`.

```plaintext
📦 <project root>
 ├ 📂 src
 │   ├ 📂 db
 │   │  ├ 📜 index.ts
 │   │  └ 📜 schema.ts
 ├ 📂 migrations
 │   ├ 📂 meta
 │   │  ├ 📜 _journal.json
 │   │  └ 📜 0000_snapshot.json
 │   └ 📜 0000_watery_spencer_smythe.sql
 ├ 📜 .env.local
 ├ 📜 drizzle.config.ts
 ├ 📜 package.json
 └ 📜 tsconfig.json
```

## Query examples

For instance, we create `src/db/queries` folder and separate files for each operation: insert, select, update, delete.

#### Insert data

Read more about insert query in the [documentation](/docs/insert).

```typescript copy filename="src/db/queries/insert.ts" {4, 8}
import { db } from '../index';
import { InsertPost, InsertUser, postsTable, usersTable } from '../schema';

export async function createUser(data: InsertUser) {
  await db.insert(usersTable).values(data);
}

export async function createPost(data: InsertPost) {
  await db.insert(postsTable).values(data);
}
```

#### Select data

Read more about select query in the [documentation](/docs/select).

<Callout type='warning'>
`getColumns` available starting from `drizzle-orm@1.0.0-beta.2`(read more [here](/docs/upgrade-v1))

If you are on pre-1 version(like `0.45.1`) then use `getTableColumns`
</Callout>

```typescript copy filename="src/db/queries/select.ts" {5, 16, 41}
import { asc, between, count, eq, getColumns, sql } from 'drizzle-orm';
import { db } from '../index';
import { SelectUser, postsTable, usersTable } from '../schema';

export async function getUserById(id: SelectUser['id']): Promise<
  Array<{
    id: number;
    name: string;
    age: number;
    email: string;
  }>
> {
  return db.select().from(usersTable).where(eq(usersTable.id, id));
}

export async function getUsersWithPostsCount(
  page = 1,
  pageSize = 5,
): Promise<
  Array<{
    postsCount: number;
    id: number;
    name: string;
    age: number;
    email: string;
  }>
> {
  return db
    .select({
      ...getColumns(usersTable),
      postsCount: count(postsTable.id),
    })
    .from(usersTable)
    .leftJoin(postsTable, eq(usersTable.id, postsTable.userId))
    .groupBy(usersTable.id)
    .orderBy(asc(usersTable.id))
    .limit(pageSize)
    .offset((page - 1) * pageSize);
}

export async function getPostsForLast24Hours(
  page = 1,
  pageSize = 5,
): Promise<
  Array<{
    id: number;
    title: string;
  }>
> {
  return db
    .select({
      id: postsTable.id,
      title: postsTable.title,
    })
    .from(postsTable)
    .where(between(postsTable.createdAt, sql`now() - interval '1 day'`, sql`now()`))
    .orderBy(asc(postsTable.title), asc(postsTable.id))
    .limit(pageSize)
    .offset((page - 1) * pageSize);
}
```

Alternatively, you can use [relational query syntax](/docs/rqb).

#### Update data

Read more about update query in the [documentation](/docs/update).

```typescript copy filename="src/db/queries/update.ts" {5}
import { eq } from 'drizzle-orm';
import { db } from '../index';
import { SelectPost, postsTable } from '../schema';

export async function updatePost(id: SelectPost['id'], data: Partial<Omit<SelectPost, 'id'>>) {
  await db.update(postsTable).set(data).where(eq(postsTable.id, id));
}
```

#### Delete data

Read more about delete query in the [documentation](/docs/delete).

```typescript copy filename="src/db/queries/delete.ts" {5}
import { eq } from 'drizzle-orm';
import { db } from '../index';
import { SelectUser, usersTable } from '../schema';

export async function deleteUser(id: SelectUser['id']) {
  await db.delete(usersTable).where(eq(usersTable.id, id));
}
```


Source: https://orm.drizzle.team/docs/tutorials/drizzle-with-xata


import Prerequisites from "@mdx/Prerequisites.astro";
import Npm from '@mdx/Npm.astro';
import Steps from '@mdx/Steps.astro';
import Section from "@mdx/Section.astro";
import Callout from '@mdx/Callout.astro';

This tutorial demonstrates how to use Drizzle ORM with [Xata](https://xata.io). Xata is a PostgreSQL database platform designed to help developers operate and scale databases with enhanced productivity and performance, featuring instant copy-on-write database branches, zero-downtime schema changes, data anonymization, and AI-powered performance monitoring.

<Prerequisites>
- You should have installed Drizzle ORM and [Drizzle kit](/docs/kit-overview). You can do this by running the following command:
<Npm>
  drizzle-orm@rc
  -D drizzle-kit@rc
</Npm>
- You should have installed `dotenv` package for managing environment variables. Read more about this package [here](https://www.npmjs.com/package/dotenv)
<Npm>
  dotenv
</Npm>

- You should have installed `postgres` package for connecting to the Postgres database. Read more about this package [here](https://www.npmjs.com/package/postgres)
<Npm>
  postgres
</Npm>

- You should have a Xata account and database set up. Follow the [Xata documentation](https://xata.io/documentation/getting-started) to create your account and database
</Prerequisites>

Check [Xata documentation](https://xata.io/documentation/quickstarts/drizzle) to learn more about using Drizzle ORM with Xata.

## Setup Xata and Drizzle ORM

<Steps>
#### Create a new Xata database

You can create a new Xata database by following these steps:

1. Sign up or log in to your [Xata account](https://xata.io/)
2. Create a new database from the dashboard
3. Choose your region and database name
4. Your database will be created with a PostgreSQL endpoint

#### Setup connection string variable

Navigate to the Xata dashboard and copy the PostgreSQL connection string. You can find this on the branch overview page.

Add `DATABASE_URL` variable to your `.env` or `.env.local` file:

```plaintext copy
DATABASE_URL=<YOUR_XATA_DATABASE_URL>
```

The connection string format will be:
```plaintext
postgresql://postgres:<password>@<branch-id>.<region>.xata.tech/<database>?sslmode=require
```

Example:
```plaintext
postgresql://postgres:password@t56hgfp7hd2sjfeiqcn66qpo8s.us-east-1.xata.tech/app?sslmode=require
```

<Callout type="info">
Xata provides branch-based development, allowing you to create isolated database branches for development, staging, and production environments.
</Callout>

#### Connect Drizzle ORM to your database

Create a `index.ts` file in the `src/db` directory and set up your database configuration:

```typescript copy filename="src/db/index.ts"
import { config } from 'dotenv';
import { drizzle } from 'drizzle-orm/postgres-js';
import postgres from 'postgres';

config({ path: '.env' }); // or .env.local

const client = postgres(process.env.DATABASE_URL!);
export const db = drizzle({ client });
```

#### Create tables

Create a `schema.ts` file in the `src/db` directory and declare your tables:

```typescript copy filename="src/db/schema.ts"
import { integer, pgTable, serial, text, timestamp } from 'drizzle-orm/pg-core';

export const usersTable = pgTable('users_table', {
  id: serial('id').primaryKey(),
  name: text('name').notNull(),
  age: integer('age').notNull(),
  email: text('email').notNull().unique(),
});

export const postsTable = pgTable('posts_table', {
  id: serial('id').primaryKey(),
  title: text('title').notNull(),
  content: text('content').notNull(),
  userId: integer('user_id')
    .notNull()
    .references(() => usersTable.id, { onDelete: 'cascade' }),
  createdAt: timestamp('created_at').notNull().defaultNow(),
  updatedAt: timestamp('updated_at')
    .notNull()
    .$onUpdate(() => new Date()),
});

export type InsertUser = typeof usersTable.$inferInsert;
export type SelectUser = typeof usersTable.$inferSelect;

export type InsertPost = typeof postsTable.$inferInsert;
export type SelectPost = typeof postsTable.$inferSelect;
```

#### Setup Drizzle config file

**Drizzle config** - a configuration file that is used by [Drizzle Kit](/docs/kit-overview) and contains all the information about your database connection, migration folder and schema files.

Create a `drizzle.config.ts` file in the root of your project and add the following content:

```typescript copy filename="drizzle.config.ts"
import { config } from 'dotenv';
import { defineConfig } from 'drizzle-kit';

config({ path: '.env' });

export default defineConfig({
  schema: './src/db/schema.ts',
  out: './migrations',
  dialect: 'postgresql',
  dbCredentials: {
    url: process.env.DATABASE_URL!,
  },
});
```

#### Applying changes to the database

You can generate migrations using `drizzle-kit generate` command and then run them using the `drizzle-kit migrate` command.

Generate migrations:

```bash copy
npx drizzle-kit generate
```

These migrations are stored in the `migrations` directory, as specified in your `drizzle.config.ts`. This directory will contain the SQL files necessary to update your database schema and a `meta` folder for storing snapshots of the schema at different migration stages.

Example of a generated migration:

```sql
CREATE TABLE IF NOT EXISTS "posts_table" (
	"id" serial PRIMARY KEY NOT NULL,
	"title" text NOT NULL,
	"content" text NOT NULL,
	"user_id" integer NOT NULL,
	"created_at" timestamp DEFAULT now() NOT NULL,
	"updated_at" timestamp NOT NULL
);
--> statement-breakpoint
CREATE TABLE IF NOT EXISTS "users_table" (
	"id" serial PRIMARY KEY NOT NULL,
	"name" text NOT NULL,
	"age" integer NOT NULL,
	"email" text NOT NULL,
	CONSTRAINT "users_table_email_unique" UNIQUE("email")
);
--> statement-breakpoint
DO $$ BEGIN
 ALTER TABLE "posts_table" ADD CONSTRAINT "posts_table_user_id_users_table_id_fk" FOREIGN KEY ("user_id") REFERENCES "users_table"("id") ON DELETE cascade ON UPDATE no action;
EXCEPTION
 WHEN duplicate_object THEN null;
END $$;
```

Run migrations:

```bash copy
npx drizzle-kit migrate
```

Learn more about [migration process](/docs/migrations).

Alternatively, you can push changes directly to the database using [Drizzle kit push command](/docs/kit-overview#prototyping-with-db-push):

```bash copy
npx drizzle-kit push
```

<Callout type="warning">Push command is good for situations where you need to quickly test new schema designs or changes in a local development environment, allowing for fast iterations without the overhead of managing migration files.</Callout>

<Callout type="info">
**Xata Branch-Based Development**: Xata allows you to create database branches for different environments. You can use different connection strings for development, staging, and production branches, making it easy to test schema changes before deploying to production.
</Callout>
</Steps>

## Basic file structure

This is the basic file structure of the project. In the `src/db` directory, we have database-related files including connection in `index.ts` and schema definitions in `schema.ts`.

```plaintext
📦 <project root>
 ├ 📂 src
 │   ├ 📂 db
 │   │  ├ 📜 index.ts
 │   │  └ 📜 schema.ts
 ├ 📂 migrations
 │   ├ 📂 meta
 │   │  ├ 📜 _journal.json
 │   │  └ 📜 0000_snapshot.json
 │   └ 📜 0000_watery_spencer_smythe.sql
 ├ 📜 .env
 ├ 📜 drizzle.config.ts
 ├ 📜 package.json
 └ 📜 tsconfig.json
```

## Query examples

For instance, we create `src/db/queries` folder and separate files for each operation: insert, select, update, delete.

#### Insert data

Read more about insert query in the [documentation](/docs/insert).

```typescript copy filename="src/db/queries/insert.ts" {4, 8}
import { db } from '../index';
import { InsertPost, InsertUser, postsTable, usersTable } from '../schema';

export async function createUser(data: InsertUser) {
  await db.insert(usersTable).values(data);
}

export async function createPost(data: InsertPost) {
  await db.insert(postsTable).values(data);
}
```

#### Select data

Read more about select query in the [documentation](/docs/select).

<Callout type='warning'>
`getColumns` available starting from `drizzle-orm@1.0.0-beta.2`(read more [here](/docs/upgrade-v1))

If you are on pre-1 version(like `0.45.1`) then use `getTableColumns`
</Callout>

```typescript copy filename="src/db/queries/select.ts" {5, 16, 41}
import { asc, between, count, eq, getColumns, sql } from 'drizzle-orm';
import { db } from '../index';
import { SelectUser, postsTable, usersTable } from '../schema';

export async function getUserById(id: SelectUser['id']): Promise<
  Array<{
    id: number;
    name: string;
    age: number;
    email: string;
  }>
> {
  return db.select().from(usersTable).where(eq(usersTable.id, id));
}

export async function getUsersWithPostsCount(
  page = 1,
  pageSize = 5,
): Promise<
  Array<{
    postsCount: number;
    id: number;
    name: string;
    age: number;
    email: string;
  }>
> {
  return db
    .select({
      ...getColumns(usersTable),
      postsCount: count(postsTable.id),
    })
    .from(usersTable)
    .leftJoin(postsTable, eq(usersTable.id, postsTable.userId))
    .groupBy(usersTable.id)
    .orderBy(asc(usersTable.id))
    .limit(pageSize)
    .offset((page - 1) * pageSize);
}

export async function getPostsForLast24Hours(
  page = 1,
  pageSize = 5,
): Promise<
  Array<{
    id: number;
    title: string;
  }>
> {
  return db
    .select({
      id: postsTable.id,
      title: postsTable.title,
    })
    .from(postsTable)
    .where(between(postsTable.createdAt, sql`now() - interval '1 day'`, sql`now()`))
    .orderBy(asc(postsTable.title), asc(postsTable.id))
    .limit(pageSize)
    .offset((page - 1) * pageSize);
}
```

Alternatively, you can use [relational query syntax](/docs/rqb).

#### Update data

Read more about update query in the [documentation](/docs/update).

```typescript copy filename="src/db/queries/update.ts" {5}
import { eq } from 'drizzle-orm';
import { db } from '../index';
import { SelectPost, postsTable } from '../schema';

export async function updatePost(id: SelectPost['id'], data: Partial<Omit<SelectPost, 'id'>>) {
  await db.update(postsTable).set(data).where(eq(postsTable.id, id));
}
```

#### Delete data

Read more about delete query in the [documentation](/docs/delete).

```typescript copy filename="src/db/queries/delete.ts" {5}
import { eq } from 'drizzle-orm';
import { db } from '../index';
import { SelectUser, usersTable } from '../schema';

export async function deleteUser(id: SelectUser['id']) {
  await db.delete(usersTable).where(eq(usersTable.id, id));
}
```

## Next Steps

Now that you have successfully set up Drizzle ORM with Xata, you can explore more advanced features:

- Learn about [Drizzle relations](/docs/rqb) for complex queries
- Explore [Xata's documentation](https://xata.io/documentation/)
- Implement [database migrations](/docs/migrations) for production deployments


Source: https://orm.drizzle.team/docs/tutorials/node-railway-pg


import Prerequisites from "@mdx/Prerequisites.astro";
import Npm from "@mdx/Npm.astro";
import Steps from "@mdx/Steps.astro";
import Section from "@mdx/Section.astro";
import Callout from "@mdx/Callout.astro";
import Shortcut from "@mdx/Shortcut.astro";

This tutorial demonstrates how to use Drizzle ORM with [Node.js](https://nodejs.org/) and a PostgreSQL database, all deployed on [Railway](https://driz.link/railway).

<Prerequisites>
  - You should have [Node.js](https://nodejs.org/) installed. You can install it by following the [official guide](https://nodejs.org/en/download/).

  - You should have installed Drizzle ORM and [Drizzle kit](/docs/kit-overview). You can do this by running the following command:
  <Npm>
      drizzle-orm@rc
      -D drizzle-kit@rc
  </Npm>

  - You should have installed the `pg` package as the PostgreSQL driver and `tsx` to run TypeScript files directly.
  <Npm>
    pg
    -D @types/pg tsx
  </Npm>

  - You should have a [Railway](https://driz.link/railway) account.
</Prerequisites>

## Setup Railway and Drizzle ORM

<Steps>
#### Create a Railway project

Log in to your [Railway dashboard](https://railway.app/dashboard) and click the `New Project` button.

![](@/assets/images/tutorials/railway-create-service-menu.png)

#### Provision a PostgreSQL database

On the project canvas, click the `New` button in the top right corner and select `Database` → `PostgreSQL`. You can also use the command palette (<Shortcut mac="⌘ K" other="Ctrl K" />) and search for PostgreSQL. Railway will provision a new PostgreSQL instance for you.

![](@/assets/images/tutorials/railway-select-postgres.png)

#### Enable public access on the database

By default, Railway keeps the database on the private network, so you cannot reach it from your machine. Click on the PostgreSQL service, go to the `Settings` tab, find the `Networking` section, and click `Add Public Access`.

![](@/assets/images/tutorials/railway-add-public-access.png)

Then click `Deploy` in the top bar to apply the change. Railway adds a public host and port, and sets the `DATABASE_PUBLIC_URL` variable on the service.

![](@/assets/images/tutorials/railway-add-public-access-apply.png)

#### Get your connection string

Go to the `Variables` tab of the PostgreSQL service and find the `DATABASE_PUBLIC_URL` variable. Copy the value — it should look similar to this:

```bash
postgresql://postgres:password@region.railway.app:port/railway
```

![](@/assets/images/tutorials/railway-postgres-variables.png)

<Callout type="warning">
Railway provides two types of database connection URLs:

- **Public URL** — accessible from anywhere (your local machine, external services). Uses a TCP proxy and looks like `postgresql://postgres:password@region.railway.app:port/railway`.
- **Private URL** — only accessible from services within the same Railway project via internal networking. Uses `*.railway.internal` hostname.

For **local development** (like running `drizzle-kit push` or `drizzle-kit studio`), you must use the **public URL**. The private `*.railway.internal` hostname will not resolve from your local machine.
</Callout>

#### Setup connection string variable

Create a `.env` file in the root of your project and add the `DATABASE_URL` environment variable. Use the **public** connection string from Railway:

```plaintext copy
DATABASE_URL=postgresql://postgres:password@region.railway.app:port/railway
```

<Callout type="info">
  This `.env` file is for local development only. When deploying to Railway, you
  will configure the `DATABASE_URL` environment variable separately in the
  Railway dashboard using a service reference variable.
</Callout>

#### Connect Drizzle ORM to your database

Create a `db.ts` file and set up your database configuration:

```typescript copy filename="src/db.ts"
import { drizzle } from "drizzle-orm/node-postgres";

export const db = drizzle(process.env.DATABASE_URL!);
```

#### Create tables

Create a `schema.ts` file and declare your tables:

```typescript copy filename="src/schema.ts"
import * as p from "drizzle-orm/pg-core";

export const usersTable = p.pgTable("users", {
  id: p.serial().primaryKey(),
  name: p.text().notNull(),
  age: p.integer().notNull(),
  email: p.text().notNull().unique(),
});

export const postsTable = p.pgTable("posts", {
  id: p.serial().primaryKey(),
  title: p.text().notNull(),
  content: p.text().notNull(),
  userId: p
    .integer()
    .notNull()
    .references(() => usersTable.id, { onDelete: "cascade" }),
  createdAt: p.timestamp().notNull().defaultNow(),
  updatedAt: p
    .timestamp()
    .notNull()
    .$onUpdate(() => new Date()),
});

export type InsertUser = typeof usersTable.$inferInsert;
export type SelectUser = typeof usersTable.$inferSelect;

export type InsertPost = typeof postsTable.$inferInsert;
export type SelectPost = typeof postsTable.$inferSelect;
```

#### Setup Drizzle config file

**Drizzle config** - a configuration file that is used by [Drizzle Kit](/docs/kit-overview) and contains all the information about your database connection, migration folder and schema files.

Create a `drizzle.config.ts` file in the root of your project and add the following content:

```typescript copy filename="drizzle.config.ts"
import { defineConfig } from "drizzle-kit";

export default defineConfig({
  schema: "./src/schema.ts",
  out: "./migrations",
  dialect: "postgresql",
  dbCredentials: {
    url: process.env.DATABASE_URL!,
  },
});
```

#### Applying changes to the database

You can generate migrations using `drizzle-kit generate` command and then run them using the `drizzle-kit migrate` command.

Generate migrations:

```bash copy
npx drizzle-kit generate
```

The `generate` command only creates migration SQL files based on your schema — it does **not** apply any changes to the database. These migrations are stored in the `migrations` directory, as specified in your `drizzle.config.ts`. This directory will contain the SQL files necessary to update your database schema and a `meta` folder for storing snapshots of the schema at different migration stages.

Example of a generated migration:

```sql
CREATE TABLE "posts" (
	"id" serial PRIMARY KEY NOT NULL,
	"title" text NOT NULL,
	"content" text NOT NULL,
	"userId" integer NOT NULL,
	"createdAt" timestamp DEFAULT now() NOT NULL,
	"updatedAt" timestamp NOT NULL
);
--> statement-breakpoint
CREATE TABLE "users" (
	"id" serial PRIMARY KEY NOT NULL,
	"name" text NOT NULL,
	"age" integer NOT NULL,
	"email" text NOT NULL,
	CONSTRAINT "users_email_unique" UNIQUE("email")
);
--> statement-breakpoint
ALTER TABLE "posts" ADD CONSTRAINT "posts_userId_users_id_fk" FOREIGN KEY ("userId") REFERENCES "public"."users"("id") ON DELETE cascade ON UPDATE no action;
```

Apply the generated migrations to the database:

```bash copy
npx drizzle-kit migrate
```

<Callout type="info">
  In this tutorial, migrations are applied automatically on application startup
  using `migrate()` from `drizzle-orm/node-postgres/migrator`. You can also
  apply them manually with `drizzle-kit migrate` for local testing.
</Callout>

Alternatively, you can push changes directly to the database using [Drizzle kit push command](/docs/kit-overview#prototyping-with-db-push):

```bash copy
npx drizzle-kit push
```

<Callout type="warning">
  Push command is good for rapid prototyping in local development, allowing fast
  iterations without managing migration files. For production deployments,
  prefer the `generate` + `migrate` workflow to keep a versioned history of
  schema changes.
</Callout>

</Steps>

## Basic file structure

This is the basic file structure of the project. In the `src` directory, we have database-related files including connection in `db.ts` and schema definitions in `schema.ts`.

```plaintext
📦 <project root>
 ├ 📂 src
 │  ├ 📜 db.ts
 │  ├ 📜 schema.ts
 │  └ 📜 index.ts
 ├ 📂 migrations
 │  ├ 📂 meta
 │  │  ├ 📜 _journal.json
 │  │  └ 📜 0000_snapshot.json
 │  └ 📜 0000_optimal_the_fury.sql
 ├ 📜 .env
 ├ 📜 drizzle.config.ts
 ├ 📜 package.json
 └ 📜 tsconfig.json
```

## Deploy the App to Railway

<Steps>
#### Prepare your project for deployment

Once you've [generated your migrations](#applying-changes-to-the-database), commit the `migrations` directory to your repository — these files will be applied automatically when your app starts.

Create an `index.ts` file as the entry point for your application. This example runs migrations on startup and then starts a simple HTTP server using Node.js:

```typescript copy filename="src/index.ts"
import { createServer } from "node:http";
import { drizzle } from "drizzle-orm/node-postgres";
import { migrate } from "drizzle-orm/node-postgres/migrator";
import { usersTable } from "./schema";

const db = drizzle(process.env.DATABASE_URL!);

await migrate(db, { migrationsFolder: "./migrations" });

const server = createServer(async (req, res) => {
  const url = new URL(req.url!, `http://${req.headers.host}`);

  if (url.pathname === "/users") {
    const users = await db.select().from(usersTable);
    res.writeHead(200, { "Content-Type": "application/json" });
    res.end(JSON.stringify(users));
    return;
  }

  res.writeHead(200);
  res.end("OK");
});

const port = process.env.PORT || 3000;
server.listen(port, () => {
  console.log(`Server running on port ${port}`);
});
```

The `migrate()` function reads the SQL files from your `migrations` directory and applies any unapplied migrations to the database. It is safe to run on every startup — already applied migrations are skipped.

<Callout type="info">
  Top-level `await` requires Node.js to treat the file as an ES module. Make
  sure your `package.json` includes `"type": "module"`.
</Callout>

Make sure your `package.json` has the module type and a start script:

```json copy filename="package.json"
{
  "type": "module",
  "scripts": {
    "start": "tsx src/index.ts"
  }
}
```

#### Push your project to GitHub

Railway deploys from a GitHub repository. Initialize a git repository and push your code:

```bash copy
git init
git add .
git commit -m "initial commit"
```

Create a new repository on GitHub and push your code to it.

#### Connect your GitHub repository to Railway

In your Railway project, click the `New` button in the top right corner of the canvas and select `GitHub Repo`. Connect your GitHub account if prompted, then select the repository you just pushed.

![](@/assets/images/tutorials/railway-canvas-postgres-add-service.png)

![](@/assets/images/tutorials/node-railway-github-repo-search.png)

#### Configure environment variables

In the deployed service settings, go to the `Variables` tab. Add the `DATABASE_URL` variable by referencing the PostgreSQL service variable:

Click `Add Variable`, set the name to `DATABASE_URL`, and use the Railway variable reference `${{Postgres.DATABASE_URL}}` as the value.

<Callout type="info">
The `${{Postgres.DATABASE_URL}}` reference variable automatically resolves to the **private** internal connection string at runtime, which is optimal for service-to-service communication within Railway. This is different from the public URL you use in your local `.env` file.
</Callout>

![](@/assets/images/tutorials/node-railway-app-set-database-url.png)

#### Deploy

Railway will automatically deploy your application when you push to the connected branch. You can monitor the deployment in the `Deployments` tab.

![](@/assets/images/tutorials/node-railway-deployment-successful.png)

#### Verify your setup

Once deployed, navigate to the `Architecture` tab in your Railway project. You should see your application service connected to the PostgreSQL database.

![](@/assets/images/tutorials/node-railway-canvas-app-postgres-full.png)

<Callout type="warning" title="Alternative: Zero-downtime migrations">
This tutorial applies migrations at application startup using `migrate()`. This is the simplest approach and works well for most applications.

If you need **zero-downtime deployments**, you may want to run migrations as a **separate step** before the new version of your app starts receiving traffic. This way you can rollback the application independently from the database changes.

On Railway, you can achieve this using a [pre-deploy command](https://docs.railway.com/deployments/pre-deploy-command) — it runs between the build and deploy phases, has access to your private network and environment variables, and if it fails, the deployment will not proceed.

In your service settings, scroll down to the **Deploy** section and click **Add pre-deploy step**:

![](@/assets/images/tutorials/node-railway-app-predeploy-migrate.png)

Enter the following command:

```bash copy
npx drizzle-kit migrate
```

With this approach, remove the `await migrate(db, { migrationsFolder: "./migrations" })` call from your `index.ts` — migrations are handled by the pre-deploy command instead.

For more details, see the [Drizzle migrations fundamentals](/docs/migrations) page.

</Callout>

</Steps>

## Deploy Drizzle Studio to Railway

You can deploy [Drizzle Studio](/drizzle-studio/overview) alongside your application on Railway to browse and manage your database directly from the browser.

### Option 1: One-click deployment (recommended)

<a
  href="https://railway.com/new/template/drizzle-studio-1?referralCode=eobqmj&utm_medium=integration&utm_source=button&utm_campaign=drizzle-studio-1"
  target="_blank"
  rel="nofollow noreferrer"
  style="display: inline-block; margin: 16px 0;"
>
  <img src="https://railway.com/button.svg" alt="Deploy on Railway" width="183" height="40" />
</a>

<Steps>
#### Choose your Railway project

Open the `Deploy to` dropdown and select the project that holds your PostgreSQL database. Deploying into the same project lets Drizzle Studio reference the database variables.

![](@/assets/images/tutorials/railway-deploy-drizzle-studio-project.png)

#### Set the database connection string

Click `Configure`, set the `DATABASE_URL` variable to `${{Postgres.DATABASE_URL}}` to reference your existing PostgreSQL service, and click `Save Config`. Then click `Review and deploy`.

![](@/assets/images/tutorials/railway-deploy-drizzle-studio-env.png)

</Steps>

### Option 2: Manual deployment

<details>
<summary style="cursor: pointer; user-select: none; margin-bottom: 16px;">Show the manual steps</summary>

<Steps>
#### Add a new service from a template

In your Railway project, click the `New` button in the top right corner of the canvas and select `Template`.

![](@/assets/images/tutorials/node-railway-canvas-postgres-add-new-service.png)

#### Select the Drizzle Studio template

Search for `drizzle studio` and select the **Drizzle Studio** template by Drizzle.

![](@/assets/images/tutorials/railway-template-search-drizzle-studio.png)

#### Configure environment variables and deploy

The template comes with three pre-configured environment variables:

- `PASSCODE` - the password for secure access to your Studio instance. It defaults to `${{secret()}}`, which generates a random secret.
- `DATABASE_URL` - the database connection string. Set it to `${{Postgres.DATABASE_URL}}` to reference your existing PostgreSQL service.
- `PORT` - the port Drizzle Studio listens on. It defaults to `4983`. Leave it as it is.

Click `Deploy Template` to deploy.

![](@/assets/images/tutorials/railway-drizzle-studio-template-config.png)

</Steps>

</details>

### After deployment

<Steps>
#### Find your Drizzle Studio URL

Once deployed, click on the Drizzle Studio service in your project, go to the `Settings` tab, and scroll down to the `Networking` section. You will find your public domain under **Public Networking**.

![](@/assets/images/tutorials/railway-drizzle-studio-networking.png)

#### Enter the passcode

Open the Drizzle Studio URL in your browser. On the first visit it asks for a passcode.

![](@/assets/images/tutorials/railway-drizzle-studio-passcode-request.png)

Go back to the Drizzle Studio service in Railway, open the `Variables` tab, and copy the value of the `PASSCODE` variable. The template generates it for you, so it is different for every deployment.

![](@/assets/images/tutorials/railway-drizzle-studio-passcode.png)

Paste the value into the prompt and click `Continue`.

#### Browse your database with Drizzle Studio

You should now see your database tables and can browse, filter, and edit data directly.

![](@/assets/images/tutorials/drizzle-studio-posts-table.png)

#### Verify your setup

Navigate to the `Architecture` tab in your Railway project. You should now see three services: your application, the PostgreSQL database, and Drizzle Studio.

![](@/assets/images/tutorials/node-railway-canvas-all-services.png)

</Steps>


Source: https://orm.drizzle.team/docs/tutorials/railway-postgres-tailscale-legacy


import Prerequisites from "@mdx/Prerequisites.astro";
import Npm from "@mdx/Npm.astro";
import Steps from "@mdx/Steps.astro";
import Callout from "@mdx/Callout.astro";
import Shortcut from "@mdx/Shortcut.astro";
import TableWrapper from "@mdx/TableWrapper.astro";
import ExternalLinkArrows from "@mdx/ExternalLinkArrows.astro";
import { Image } from "astro:assets";
import diagramLight from "@/assets/images/tutorials/railway-postgres-tailscale-diagram-light.png";
import diagramDark from "@/assets/images/tutorials/railway-postgres-tailscale-diagram-dark.png";

<style>{`
  .tailscale-diagram-light,
  .tailscale-diagram-dark {
    width: 100%;
    height: auto;
    margin: 16px 0;
  }
  .tailscale-diagram-dark {
    display: none;
  }
  html[class~="dark"] .tailscale-diagram-light {
    display: none;
  }
  html[class~="dark"] .tailscale-diagram-dark {
    display: block;
  }
`}</style>

<ExternalLinkArrows />

<Callout type="error" title="Outdated guide" highlighted>
Drizzle now has a Railway template that includes its own Tailscale forwarder, which makes the setup simpler. Follow the latest version of this guide: [Run Drizzle Kit against a private Railway database over Tailscale](/docs/tutorials/railway-postgres-tailscale).
</Callout>

This tutorial runs a PostgreSQL database on [Railway](https://driz.link/railway) with public access turned off, and connects `drizzle-kit` to it from your machine.

A [Tailscale](https://tailscale.com/) Forwarder joins your tailnet and forwards the database port into Railway's private network. Nothing is exposed to the public internet, and every device on your tailnet can run migrations against the database.

<Prerequisites title="This guide assumes the following:">
  - You have a [Railway](https://driz.link/railway) account.

  - You have a [Tailscale](https://tailscale.com/) account.

  - You have the Tailscale client installed on the machine you work from, and that machine is signed in to your tailnet. You can find the downloads on the [Tailscale website](https://tailscale.com/download).

  - You have installed Drizzle ORM and [Drizzle Kit](/docs/kit-overview).
  <Npm>
      drizzle-orm@rc
      -D drizzle-kit@rc
  </Npm>
</Prerequisites>

## How it works

Railway gives every service a private domain that ends in `.railway.internal`. Those domains resolve only inside the project, so `drizzle-kit` on your machine cannot use them.

The Tailscale Forwarder solves that from both sides. It runs as a service in the same Railway project, so it resolves the private domains. It also joins your tailnet as a machine, so your own devices reach it by its tailnet name. Traffic goes from `drizzle-kit` over the tailnet to the forwarder, and from the forwarder to the database over Railway's private network.

<Image class="tailscale-diagram-light" src={diagramLight} alt="" />
<Image class="tailscale-diagram-dark" src={diagramDark} alt="" />

## Set up the Railway project

<Steps>
#### Create a Railway project

Log in to your [Railway dashboard](https://railway.app/dashboard) and click the `New Project` button.

![](@/assets/images/tutorials/railway-create-service-menu.png)

#### Provision a PostgreSQL database

On the project canvas, click the `New` button in the top right corner and select `Database` → `PostgreSQL`. You can also use the command palette (<Shortcut mac="⌘ K" other="Ctrl K" />) and search for PostgreSQL.

![](@/assets/images/tutorials/railway-select-postgres.png)

#### Keep the database on the private network

Click on the PostgreSQL service, go to the `Settings` tab, and find the `Networking` section. Verify that public access is disabled. Under `Private Networking` you will see the private domain of the service, for example `postgres.railway.internal`. The forwarder will use that domain.

![](@/assets/images/tutorials/railway-postgres-private-networking.png)

</Steps>

## Add the database to your tailnet

<Steps>
#### Check MagicDNS and HTTPS certificates

Open the [DNS page](https://login.tailscale.com/admin/dns) in the Tailscale admin console. Both **MagicDNS** and **HTTPS Certificates** must be enabled. Each section offers the opposite action, so a button that reads `Disable MagicDNS...` means MagicDNS is already on.

MagicDNS gives the forwarder a stable machine name, which the database connection needs. HTTPS certificates are not needed for the database connection, but they are needed to open a database UI over the forwarder, and both settings live on this page.

![](@/assets/images/tutorials/tailscale-dns-magicdns-https.png)

#### Create a reusable auth key

Go to the [Keys page](https://login.tailscale.com/admin/settings/keys) in the settings menu and click `Generate auth key`. Add a description and turn on `Reusable`. Leave the other settings as they are. A reusable key lets the forwarder register itself again when it starts without existing state.

![](@/assets/images/tutorials/tailscale-generate-auth-key.png)

Click `Generate key`. Copy the key now, because the admin console shows it only once.

![](@/assets/images/tutorials/tailscale-auth-key-created.png)

#### Deploy the Tailscale Forwarder

The Tailscale Forwarder is a small TCP proxy. It joins your tailnet as a machine and forwards ports on that machine to services on the Railway private network. Railway publishes the template, and it runs the `brody192/tailscale-forwarder` image.

<a
  href="https://railway.com/deploy/tailscale-forwarder"
  target="_blank"
  rel="nofollow noreferrer"
  style="display: inline-block; margin: 16px 0;"
>
  <img src="https://railway.com/button.svg" alt="Deploy on Railway" width="183" height="40" />
</a>

Open the `Deploy to` dropdown and select the project that holds your database. Both services must be in the same project, otherwise the forwarder won't be able to reach the database over the private network, since it will be placed on a different private network.

Paste your auth key into `TS_AUTHKEY`. Then set `CONNECTION_MAPPING_01` to the database mapping. The format is `[https:]<source port>:<target host>:<target port>`.

```plaintext copy
5432:${{Postgres.RAILWAY_PRIVATE_DOMAIN}}:${{Postgres.PGPORT}}
```

This forwards port `5432` on the forwarder to your database.

![](@/assets/images/tutorials/railway-tailscale-forwarder-template-config.png)

<Callout type="info">
The template setup screen shows only the variables the template declares, and you cannot add new ones there. `CONNECTION_MAPPING_01` is the only mapping you can set now. You add further mappings on the service itself, after it exists.
</Callout>

#### Deploy and check the logs

Click `Deploy`. The template attaches a volume and sets `TS_EPHEMERAL=false`, so the machine keeps the same identity across redeploys instead of registering a duplicate.

Open the `Deployments` tab and read the deploy logs. Three lines tell you the forwarder started correctly:

- `tsnet starting with hostname "..."` gives the machine name on your tailnet. You need it in a later step.
- `Starting tailscale_fwdr` lists what it parsed, including `ts-ephemeral: false` and the source port, target address and target port of each mapping.
- `listening for connections` confirms the forwarder accepts traffic on that source port.

![](@/assets/images/tutorials/railway-tailscale-forwarder-logs.png)

#### Copy the forwarder domain

`TS_HOSTNAME` defaults to your project name, environment name and service name joined by dashes, for example `my-project-production-tailscale-forwarder`. The deploy log prints it on the `tsnet starting with hostname` line.

Open the [Machines page](https://login.tailscale.com/admin/machines) in the Tailscale admin console. The forwarder appears there on its own once it starts with a valid auth key.

![](@/assets/images/tutorials/tailscale-machines-forwarder.png)

Click the machine to open its page. Under `Machine Details`, copy the `Full domain` value. That is the host you connect to from your machine.

![](@/assets/images/tutorials/tailscale-machine-full-domain.png)

</Steps>

## Connect Drizzle Kit from your machine

<Callout type="warning">
The machine you run `drizzle-kit` on must be signed in to the same tailnet as the forwarder, because the database connection is routed through it.
</Callout>

<Steps>
#### Set the connection string

Open the PostgreSQL service in Railway, go to the `Variables` tab, and copy `DATABASE_URL`.

![](@/assets/images/tutorials/railway-postgres-database-url.png)

Replace the `***.railway.internal` host with the [Tailscale forwarder's domain](#copy-the-forwarder-domain) and keep the rest of the string. `railway.internal` cannot be resolved on a machine outside Railway, so you need to connect through the Tailscale forwarder. Put the result in a `.env` file.

```plaintext copy
DATABASE_URL=postgresql://postgres:password@<full-domain>:5432/railway
```

<Callout type="info">
Tailscale encrypts the connection between your machine and the forwarder, and Railway encrypts the hop between the forwarder and the database. Railway's PostgreSQL also accepts TLS through the forwarder, so most clients connect with their default settings.
</Callout>

#### Set up the Drizzle config file

Create a `drizzle.config.ts` file in the root of your project:

```typescript copy filename="drizzle.config.ts"
import { defineConfig } from "drizzle-kit";

export default defineConfig({
  schema: "./src/schema.ts",
  out: "./migrations",
  dialect: "postgresql",
  dbCredentials: {
    url: process.env.DATABASE_URL!,
  },
});
```

#### Apply your schema

Generate migrations and apply them:

```bash copy
npx drizzle-kit generate
```

```bash copy
npx drizzle-kit migrate
```

For rapid prototyping you can push the schema directly with [drizzle-kit push](/docs/kit-overview#prototyping-with-db-push). For production deployments, prefer the `generate` and `migrate` workflow, so you keep a versioned history of schema changes. See the [Drizzle migrations fundamentals](/docs/migrations) page for details.

#### Check the result

Open the database in [Drizzle Studio](/docs/drizzle-kit-studio):

```bash copy
npx drizzle-kit studio
```

It runs on your machine and reads the same `DATABASE_URL`, so it reaches the database through the forwarder. Your new tables are there.

![](@/assets/images/tutorials/drizzle-studio-posts-table.png)

</Steps>

<Callout type="info">
For occasional access you do not need Tailscale at all. The Railway CLI opens a temporary tunnel to a private database with `railway connect Postgres --tunnel-only`. A forwarder is the right tool when you need a permanent route, or access from every device on your tailnet.
</Callout>

## Next steps

The forwarder can carry more than one port. ["Drizzle Studio and Gateway on Railway behind Tailscale"](/docs/tutorials/railway-studio-tailscale-legacy) tutorial deploys a database UI into the same Railway project and adds a second mapping for it, so you browse your tables from your tailnet without a public domain. That tutorial starts from an empty project, so with the forwarder already running you can go straight to the template deployment and the second mapping.

## Troubleshooting

<Callout>
<Fragment slot="collapsed-title">The forwarder is not in the Machines list</Fragment>

The auth key expired, or a key that was not reusable had already been used. Generate a new reusable key, update `TS_AUTHKEY` on the forwarder service, and redeploy.
</Callout>

<Callout>
<Fragment slot="collapsed-title">`drizzle-kit` cannot connect</Fragment>

Run `tailscale status` and check that your device is signed in to the same tailnet. Check that the port in your connection string matches the source port in `CONNECTION_MAPPING_01`. Railway's PostgreSQL accepts TLS through the forwarder, so you do not need to disable SSL.
</Callout>

<Callout>
<Fragment slot="collapsed-title">The mapping variable is ignored</Fragment>

Confirm the exact variable name on the forwarder service. The template declares `CONNECTION_MAPPING_01`, with a leading zero. Some older guides write `CONNECTION_MAPPING_1`. Use the form the config panel shows you, and keep the numbers unique.
</Callout>


Source: https://orm.drizzle.team/docs/tutorials/railway-postgres-tailscale


import Prerequisites from "@mdx/Prerequisites.astro";
import Npm from "@mdx/Npm.astro";
import Steps from "@mdx/Steps.astro";
import Callout from "@mdx/Callout.astro";
import Shortcut from "@mdx/Shortcut.astro";
import TableWrapper from "@mdx/TableWrapper.astro";
import ExternalLinkArrows from "@mdx/ExternalLinkArrows.astro";
import { Image } from "astro:assets";
import diagramLight from "@/assets/images/tutorials/railway-tailscale-database-diagram-light.png";
import diagramDark from "@/assets/images/tutorials/railway-tailscale-database-diagram-dark.png";

<style>{`
  .tailscale-diagram-light,
  .tailscale-diagram-dark {
    width: 100%;
    height: auto;
    margin: 16px 0;
  }
  .tailscale-diagram-dark {
    display: none;
  }
  html[class~="dark"] .tailscale-diagram-light {
    display: none;
  }
  html[class~="dark"] .tailscale-diagram-dark {
    display: block;
  }
`}</style>

<ExternalLinkArrows />

This tutorial connects `drizzle-kit` on your device to a PostgreSQL database on [Railway](https://driz.link/railway) that has public access turned off.

You add a [Tailscale](https://tailscale.com/) service to the project that holds the database. Every device on your tailnet can then access the database.

<Callout type="info">
If you also want a database UI on your tailnet, start with [Deploy Drizzle Studio or Gateway on Railway with private access over Tailscale](/docs/tutorials/railway-studio-tailscale). Its templates come with the same Tailscale service.
</Callout>

<Prerequisites title="This guide assumes the following:">
  - You have a [Railway](https://driz.link/railway) account.

  - You have a [Tailscale](https://tailscale.com/) account.

  - You have the Tailscale client installed on the device you work from, and that device is signed in to your tailnet. You can find the downloads on the [Tailscale website](https://tailscale.com/download).

  - MagicDNS is on in your tailnet, so that the machine name resolves. Tailnets created on or after 2022-10-20 have it on by default. If your tailnet is older, check the [DNS page](https://login.tailscale.com/admin/dns).

  - You have installed Drizzle ORM and [Drizzle Kit](/docs/kit-overview).
  <Npm>
      drizzle-orm@rc
      -D drizzle-kit@rc
  </Npm>
</Prerequisites>

## How it works

Railway gives every service a private domain that ends in `.railway.internal`. Those domains resolve only inside the project, so `drizzle-kit` on your device cannot use them.

The Tailscale service connects the two networks. It runs in the same Railway project, so it resolves the private domains. It also joins your tailnet as a machine, so your own devices reach it by its machine name. Traffic goes from `drizzle-kit` over the tailnet to that machine, and from there to the database over Railway's private network.

<Image class="tailscale-diagram-light" src={diagramLight} alt="drizzle-kit reaches the Tailscale service over the tailnet. Inside the Railway private network, the Tailscale service reaches Postgres." />
<Image class="tailscale-diagram-dark" src={diagramDark} alt="drizzle-kit reaches the Tailscale service over the tailnet. Inside the Railway private network, the Tailscale service reaches Postgres." />

## Set up the Railway project

Create a project with a PostgreSQL database that has no public access. If your project already has a database, skip to [Add the Tailscale service](#add-the-tailscale-service).

<Steps>
#### Create a Railway project

Log in to your [Railway dashboard](https://railway.app/dashboard) and click the `New Project` button.

![Railway create menu with Database selected](@/assets/images/tutorials/railway-create-service-menu.png)

#### Provision a PostgreSQL database

On the project canvas, click the `New` button in the top right corner and select `Database` → `PostgreSQL`. You can also use the command palette (<Shortcut mac="⌘ K" other="Ctrl K" />) and search for PostgreSQL.

![Railway database menu with PostgreSQL selected](@/assets/images/tutorials/railway-select-postgres.png)

#### Keep the database on the private network

Click on the PostgreSQL service, go to the `Settings` tab, and find the `Networking` section. Verify that public access is disabled. Under `Private Networking` you will see the private domain of the service, for example `postgres.railway.internal`.

![Postgres Settings tab with no public access and the private domain postgres.railway.internal](@/assets/images/tutorials/railway-postgres-private-networking.png)

</Steps>

## Add the Tailscale service

Deploy the Tailscale for Drizzle template into the project that holds your database.

<Callout type="info">
If your project already runs `Drizzle Studio with Tailscale` or `Drizzle Gateway with Tailscale` template, it already has a Tailscale service, and you can skip this section. Open that Tailscale service, go to the `Variables` tab, and set `TS_FORWARD_DATABASE`: type `${{` and pick `RAILWAY_PRIVATE_DOMAIN` of your database service. Click `Deploy` in the top bar and wait for `5432: ready` in the new deploy log. The machine name is the first part of the address in the `open` line, for example `drizzle-studio`.
</Callout>

<Steps>
#### Open the template

Press the button below to open the Tailscale for Drizzle template.

**Don't deploy it right away.** Set the variables first.

<a
  href="https://railway.com/new/template/tailscale-for-drizzle?referralCode=eobqmj&utm_medium=integration&utm_source=button&utm_campaign=tailscale-for-drizzle"
  target="_blank"
  rel="nofollow noreferrer"
  style="display: inline-block; margin: 16px 0;"
>
  <img src="https://railway.com/button.svg" alt="Deploy on Railway" width="183" height="40" />
</a>

Open the `Deploy to` dropdown and select the project that holds your database.

![Tailscale for Drizzle deploy form with TS_FORWARD_DATABASE set to the Postgres private domain and TS_HOSTNAME set to railway-postgres](@/assets/images/tutorials/railway-tailscale-database-template-form.png)

#### Set the variables

<TableWrapper>

| Variable | What to set |
| --- | --- |
| `TS_FORWARD_DATABASE` | The field is empty. Pick your database service from the list, then pick `RAILWAY_PRIVATE_DOMAIN`. For a service named `Postgres` the field then reads `${{Postgres.RAILWAY_PRIVATE_DOMAIN}}`. |
| `TS_HOSTNAME` | Change it to `railway-postgres`, or pick another name for the machine. You connect to the database by this name. |

</TableWrapper>

Some variables, such as `TS_HOSTNAME`, are in the collapsed `Pre-Configured Environment Variables` section of the card. Expand it to see or change them.

#### Deploy the template

On the service card, click `Save Config`. Then click `Review and deploy`. Railway opens your project with the template in a side panel. Click `Deploy Template` there.

#### Sign in from the deploy log

Open the `Tailscale` service, then its `Deployments` tab, and read the deploy log. The last lines of the log hold a sign-in link:

```plaintext
This service is not on your tailnet yet. Open this link and sign in
with the account that owns your tailnet:
  https://login.tailscale.com/a/xxxxxxxxxxxx
```

Open the link and sign in. Anyone who opens that link first gets this machine on their tailnet, so do not forward it. The log is visible only to members of your Railway project.

![Tailscale deploy log with the sign-in message and a hidden link](@/assets/images/tutorials/railway-tailscale-signin-log.png)

If your tailnet requires device approval, the log says so and the machine waits until you approve it on the [Machines page](https://login.tailscale.com/admin/machines).

#### Check the forwarding rule

A few seconds after you sign in, the same log prints:

```plaintext
joined tailnet: example.com
5432: ready
```

![Tailscale deploy log with the joined tailnet and 5432 ready lines](@/assets/images/tutorials/railway-tailscale-database-log.png)

Check that the tailnet name is yours. If it is not, someone else opened the sign-in link first, and their tailnet can now reach this service. To take the service back:

1. On the project canvas, click the volume under the Tailscale service, open its `Settings` tab, and click `Wipe volume`.
2. Type the confirmation text and click `Wipe`. Railway deletes the machine's key and redeploys the service.
3. Open the sign-in link from the new deploy log yourself.
4. Change the database user's password.

#### Find the machine name

Open the [Machines page](https://login.tailscale.com/admin/machines). The new machine has the name you set in `TS_HOSTNAME`. If your tailnet already had a machine with that name, the new name ends in `-1`, `-2` and so on. Use the name that the Machines page shows.

</Steps>

## Connect Drizzle Kit from your device

Point `drizzle-kit` at the machine name and apply your schema.

<Steps>
#### Set the connection string

Open the PostgreSQL service in Railway, go to the `Variables` tab, and copy `DATABASE_URL`.

![Postgres Variables tab with DATABASE_URL marked](@/assets/images/tutorials/railway-postgres-database-url.png)

Replace the `***.railway.internal` host with the machine name and keep the rest of the string. Put the result in a `.env` file:

```plaintext copy
DATABASE_URL=postgresql://postgres:PASSWORD@MACHINE_NAME:5432/railway
```

Replace the following:

- `PASSWORD`: the password from the `DATABASE_URL` that you copied
- `MACHINE_NAME`: the machine name from the Machines page, for example `railway-postgres`

<Callout type="info">
Tailscale encrypts the connection between your device and the Tailscale service, and Railway encrypts the hop between the Tailscale service and the database. Railway's PostgreSQL also accepts TLS through the Tailscale service, so most clients connect with their default settings.
</Callout>

#### Set up the Drizzle config file

Create a `drizzle.config.ts` file in the root of your project:

```typescript copy filename="drizzle.config.ts"
import { defineConfig } from "drizzle-kit";

export default defineConfig({
  schema: "./src/schema.ts",
  out: "./migrations",
  dialect: "postgresql",
  dbCredentials: {
    url: process.env.DATABASE_URL!,
  },
});
```

#### Apply your schema

Generate migrations and apply them:

```bash copy
npx drizzle-kit generate
```

```bash copy
npx drizzle-kit migrate
```

For rapid prototyping you can push the schema directly with [drizzle-kit push](/docs/drizzle-kit-push). For production deployments, prefer the `generate` and `migrate` workflow, so you keep a versioned history of schema changes. See the [Drizzle migrations fundamentals](/docs/migrations) page for details.

#### Check the tables in Drizzle Studio

Open the database in [Drizzle Studio](/docs/drizzle-kit-studio):

```bash copy
npx drizzle-kit studio
```

It runs on your device and reads the same `DATABASE_URL`, so it reaches the database through the Tailscale service. Your new tables are there.

![Drizzle Studio with the posts and users tables](@/assets/images/tutorials/drizzle-studio-posts-table.png)

</Steps>

<Callout type="info">
For occasional access you do not need Tailscale at all. The Railway CLI opens a temporary tunnel to a private database with `railway connect Postgres --tunnel-only`. If you need a permanent route, or access from every device on your tailnet, use the Tailscale service.
</Callout>

## Use other ports

By default, `TS_FORWARD_DATABASE` uses port 5432, on the machine and on the database service. To use other ports, write the value in the form `[port:]host[:port]`:

<TableWrapper>

| Value | Port on the machine | Port on the service |
| --- | --- | --- |
| `host` | The default port | The default port |
| `host:port` | `port` | `port` |
| `source_port:host:target_port` | `source_port` | `target_port` |

</TableWrapper>

For example, `5433:${{Postgres.RAILWAY_PRIVATE_DOMAIN}}:5432` forwards port 5433 on the machine to port 5432 of the database service. Your connection string then uses port 5433.

## Disable key expiry

A machine that joined by signing in has its key expire on your tailnet's schedule, 180 days by default. When that happens, the Tailscale service prints a new sign-in link and waits. The machine is unreachable until you click it.

To avoid that, open the [Machines page](https://login.tailscale.com/admin/machines) once, find the machine, open the menu at the far right of its row, and choose `Disable key expiry`.

![Tailscale Machines page menu with Disable key expiry](@/assets/images/tutorials/tailscale-machines-disable-key-expiry.png)

<Callout type="info">
If you automate deployments and want no sign-in at all, set `TS_AUTHKEY` on the Tailscale service:

- For an auth key, set `TS_AUTHKEY` to the key.
- For an OAuth client secret, set `TS_AUTHKEY` to the secret with `?ephemeral=false&preauthorized=true` appended. Without that suffix, Tailscale removes the machine when it disconnects, and the machine waits for approval before it joins. Also set `TS_TAGS` to a tag you own, for example `tag:drizzle`. A tagged machine never has its key expire.

The Tailscale service reads `TS_AUTHKEY` only before the machine joins. If the machine has already joined, remove the machine and wipe the volume first.
</Callout>

## Troubleshoot the Tailscale setup

Open the entry that matches what you see.

<Callout>
<Fragment slot="collapsed-title">The error names a host that ends in `.railway.internal`</Fragment>

The `DATABASE_URL` you copied from Railway still carries the private domain, which resolves only inside the project. Replace that host with the Tailscale machine name and keep the rest of the string, as in [Set the connection string](#set-the-connection-string).
</Callout>

<Callout>
<Fragment slot="collapsed-title">`drizzle-kit` cannot connect</Fragment>

Run `tailscale status` on your device and check that it is signed in to the same tailnet the log named. Then open the Tailscale service's deploy log and find the cause:

- A line starts with `5432:` and ends in a network error, such as `connect: connection refused` or `no such host`. The variable is correct, and the database is unreachable on its private domain. Check that the database service is running and has private networking on. If the database listens on another port, add the port to the value, for example `5432:${{Postgres.RAILWAY_PRIVATE_DOMAIN}}:5433`.
- No line starts with `5432:` or `TS_FORWARD_DATABASE`. The variable is empty, or its reference names a service outside your project. Set it on the Tailscale service's `Variables` tab and click `Deploy` in the top bar.
- A line starts with `TS_FORWARD_DATABASE`. The next entry explains that line.
- The log shows `5432: ready`, and the machine name does not resolve. Check that MagicDNS is on, on the [DNS page](https://login.tailscale.com/admin/dns). If it is on, use the machine's `Full domain` value from the Machines page as the host.
</Callout>

<Callout>
<Fragment slot="collapsed-title">The log prints a line that ends in `skipped`</Fragment>

The line starts with the variable name, then gives the reason:

- `does not match [port:]host[:port]`: the value has more than two colons.
- `has an empty target host`: the value has a port but no host. A reference that names a service outside your project resolves to an empty host.
- `still contains a Railway reference that did not resolve`: Railway did not replace the reference. Check the service name inside it.
- `has a port outside 1-65535`: a port is not a number from 1 to 65535.
- `reuses port`: an earlier forward already uses that port on the machine.
- `uses port 443, which the https listener owns`: pick another port on the machine. The address of the database UI already uses 443 when HTTPS certificates are on.

Fix the value on the Tailscale service's `Variables` tab and click `Deploy` in the top bar.
</Callout>

<Callout>
<Fragment slot="collapsed-title">A new sign-in link appeared in the log</Fragment>

The service restarted, for example after the key expired or the machine was removed. Open the newest link. The link works once.
</Callout>

<Callout>
<Fragment slot="collapsed-title">The log says the machine is waiting for approval</Fragment>

Your tailnet has device approval turned on. Open the [Machines page](https://login.tailscale.com/admin/machines) and approve it.
</Callout>

<Callout>
<Fragment slot="collapsed-title">It worked for months and then stopped</Fragment>

The machine's key expired. Open the Tailscale service's deploy log; it is printing a fresh sign-in link. Click it, then disable key expiry on the machine so it does not happen again.
</Callout>

<Callout>
<Fragment slot="collapsed-title">The machine name gained a `-1` suffix</Fragment>

Your tailnet already had a machine with this name, for example from an earlier deploy. Tailscale keeps the suffix. If you want the short name, rename the machine on the Machines page. Otherwise, use the name that the Machines page shows.
</Callout>

## Next steps

- [Drizzle migrations fundamentals](/docs/migrations) to choose between `generate`, `migrate` and `push`.
- [Deploy Drizzle Studio or Gateway on Railway with private access over Tailscale](/docs/tutorials/railway-studio-tailscale) to browse the database from your tailnet.


Source: https://orm.drizzle.team/docs/tutorials/railway-studio-tailscale-legacy


import Prerequisites from "@mdx/Prerequisites.astro";
import Steps from "@mdx/Steps.astro";
import Callout from "@mdx/Callout.astro";
import Shortcut from "@mdx/Shortcut.astro";
import Tabs from "@mdx/Tabs.astro";
import Tab from "@mdx/Tab.astro";
import TableWrapper from "@mdx/TableWrapper.astro";
import ExternalLinkArrows from "@mdx/ExternalLinkArrows.astro";
import { Image } from "astro:assets";
import diagramLight from "@/assets/images/tutorials/railway-studio-tailscale-diagram-light.png";
import diagramDark from "@/assets/images/tutorials/railway-studio-tailscale-diagram-dark.png";

<style>{`
  .tailscale-diagram-light,
  .tailscale-diagram-dark {
    width: 100%;
    height: auto;
    margin: 16px 0;
  }
  .tailscale-diagram-dark {
    display: none;
  }
  html[class~="dark"] .tailscale-diagram-light {
    display: none;
  }
  html[class~="dark"] .tailscale-diagram-dark {
    display: block;
  }
`}</style>

<ExternalLinkArrows />

<Callout type="error" title="Outdated guide" highlighted>
Drizzle now has Railway templates that include their own Tailscale forwarders, which makes the setup simpler. To start from scratch, follow [Deploy Drizzle Studio or Gateway on Railway with private access over Tailscale](/docs/tutorials/railway-studio-tailscale). If you already run Drizzle Studio or Gateway on Railway, follow [Add private access to Drizzle Studio, Gateway or a database on Railway with Tailscale](/docs/tutorials/railway-tailscale-existing-project).
</Callout>

This tutorial deploys a database UI and a PostgreSQL database on [Railway](https://driz.link/railway), and keeps both off the public internet.

A [Tailscale](https://tailscale.com/) Forwarder joins your tailnet and forwards the UI port into Railway's private network. After that, you open the database UI over HTTPS from any device on your tailnet, with no public domain on either service.

You can use either [Drizzle Studio](/drizzle-studio/overview) or Drizzle Gateway. Both are covered in full below.

If you want the same private access for `drizzle-kit` and other database clients, see [Connect to a private Railway database with Tailscale](/docs/tutorials/railway-postgres-tailscale-legacy).

<Prerequisites title="This guide assumes the following:">
  - You have a [Railway](https://driz.link/railway) account.

  - You have a [Tailscale](https://tailscale.com/) account.

  - You have the Tailscale client installed on the machine you work from, and that machine is signed in to your tailnet. You can find the downloads on the [Tailscale website](https://tailscale.com/download).

</Prerequisites>

## How it works

Railway gives every service a private domain that ends in `.railway.internal`. Those domains resolve only inside the project. The Tailscale Forwarder runs as a service in the same project, so it can reach them. It also joins your tailnet as a machine, so your own devices can reach it.

<Image class="tailscale-diagram-light" src={diagramLight} alt="" />
<Image class="tailscale-diagram-dark" src={diagramDark} alt="" />

## Set up the Railway project

<Steps>
#### Create a Railway project

Log in to your [Railway dashboard](https://railway.app/dashboard) and click the `New Project` button.

![](@/assets/images/tutorials/railway-create-service-menu.png)

#### Provision a PostgreSQL database

On the project canvas, click the `New` button in the top right corner and select `Database` → `PostgreSQL`. You can also use the command palette (<Shortcut mac="⌘ K" other="Ctrl K" />) and search for PostgreSQL.

![](@/assets/images/tutorials/railway-select-postgres.png)

#### Keep the database on the private network

Click on the PostgreSQL service, go to the `Settings` tab, and find the `Networking` section. Verify that public access is disabled. Under `Private Networking` you will see the private domain of the service, for example `postgres.railway.internal`. The forwarder will use that domain.

![](@/assets/images/tutorials/railway-postgres-private-networking.png)

</Steps>

## Choose Gateway or Studio

Drizzle has two Railway templates, designed for different use cases.

<TableWrapper>

| | Drizzle Studio | Drizzle Gateway |
| --- | --- | --- |
| Databases | One, fixed to the `DATABASE_URL` you set in Railway | Many, you add and edit them in the UI |
| Access | `PASSCODE` generated by the template | `MASTERPASS`, plus passcodes you hand out |

</TableWrapper>

Pick **Drizzle Studio** when:
- Everyone on your tailnet must only have access to a single database

<br />

Pick **Drizzle Gateway** when:
- You need to manage several databases
- You want to give other people access to specific databases

Keep in mind that a Gateway user who knows `MASTERPASS` can add a connection to any database the service can reach.

<br />

<Tabs items={['Drizzle Studio', 'Drizzle Gateway']}>
<Tab>

<Steps>
#### Deploy the Studio template into the same project

Press the button below to open the Drizzle Studio template.

**Don't deploy it right away** - make sure to read this step to the end first and set the required variables.

<a
  href="https://railway.com/new/template/drizzle-studio-1?referralCode=eobqmj&utm_medium=integration&utm_source=button&utm_campaign=drizzle-studio-1"
  target="_blank"
  rel="nofollow noreferrer"
  style="display: inline-block; margin: 16px 0;"
>
  <img src="https://railway.com/button.svg" alt="Deploy on Railway" width="183" height="40" />
</a>

Open the `Deploy to` dropdown and select the project that holds your database. Both services must be in the same project, otherwise Studio won't be able to reach the database over the private network, since it will be placed on a different private network.

The template comes with three variables. Set `DATABASE_URL` to `${{Postgres.DATABASE_URL}}`, which resolves to the private connection string of the database, so Drizzle Studio reaches it over the Railway private network. `PASSCODE` guards access to the UI and the template generates it. `PORT` is set to `4983`; leave it as it is, because the forwarder mapping you add later points at the same number. Click `Deploy`.

![](@/assets/images/tutorials/railway-deploy-drizzle-studio-env.png)

#### Remove the public domain

Go to the `Settings` tab of the Drizzle Studio service and find the `Networking` section. If Railway generated a public domain, remove it. Keep the private domain. After this step the UI is reachable only from inside the project, and soon from your tailnet.

![](@/assets/images/tutorials/railway-drizzle-studio-remove-public-domain.png)

#### Check MagicDNS and HTTPS certificates

Open the [DNS page](https://login.tailscale.com/admin/dns) in the Tailscale admin console. Both **MagicDNS** and **HTTPS Certificates** must be enabled. Each section offers the opposite action, so a button that reads `Disable MagicDNS...` means MagicDNS is already on. MagicDNS gives the forwarder a stable machine name. HTTPS certificates let the forwarder serve the UI over HTTPS.

![](@/assets/images/tutorials/tailscale-dns-magicdns-https.png)

#### Create a reusable auth key

Go to the [Keys page](https://login.tailscale.com/admin/settings/keys) in the settings menu and click `Generate auth key`. Add a description and turn on `Reusable`. Leave the other settings as they are. A reusable key lets the forwarder register itself again when it starts without existing state.

![](@/assets/images/tutorials/tailscale-generate-auth-key.png)

Click `Generate key`. Copy the key now, because the admin console shows it only once.

![](@/assets/images/tutorials/tailscale-auth-key-created.png)

#### Deploy the Tailscale Forwarder

The Tailscale Forwarder is a small TCP proxy. It joins your tailnet as a machine and forwards ports on that machine to services on the Railway private network. Railway publishes the template, and it runs the `brody192/tailscale-forwarder` image.

<a
  href="https://railway.com/deploy/tailscale-forwarder"
  target="_blank"
  rel="nofollow noreferrer"
  style="display: inline-block; margin: 16px 0;"
>
  <img src="https://railway.com/button.svg" alt="Deploy on Railway" width="183" height="40" />
</a>

Paste your auth key into `TS_AUTHKEY`. Then set `CONNECTION_MAPPING_01` to the database mapping. The format is `[https:]<source port>:<target host>:<target port>`.

```plaintext copy
5432:${{Postgres.RAILWAY_PRIVATE_DOMAIN}}:${{Postgres.PGPORT}}
```

This forwards port `5432` on the forwarder to your database.

![](@/assets/images/tutorials/railway-tailscale-forwarder-template-config.png)

<Callout type="info">
The template setup screen shows only the variables the template declares, and you cannot add new ones there. `CONNECTION_MAPPING_01` is the only mapping you can set now. You will add the second one after the service exists.
</Callout>

#### Deploy and check the logs

Click `Deploy`. The template attaches a volume and sets `TS_EPHEMERAL=false`, so the machine keeps the same identity across redeploys instead of registering a duplicate.

Open the `Deployments` tab and read the deploy logs. Three lines tell you the forwarder started correctly:

- `tsnet starting with hostname "..."` gives the machine name on your tailnet. You need it in a later step.
- `Starting tailscale_fwdr` lists what it parsed, including `ts-ephemeral: false` and the source port, target address and target port of each mapping.
- `listening for connections` confirms the forwarder accepts traffic on that source port.

![](@/assets/images/tutorials/railway-tailscale-forwarder-logs.png)

#### Add the mapping for the UI

Open the `Variables` tab of the Tailscale Forwarder service and add a second mapping. Increase the number for every mapping you add, and keep the source ports unique.

<TableWrapper>

| Variable | Value |
| --- | --- |
| `CONNECTION_MAPPING_02` | `https:4983:${{Drizzle Studio.RAILWAY_PRIVATE_DOMAIN}}:4983` |

</TableWrapper>

This forwards port `4983` on the forwarder to the UI. Both numbers are `4983`: the port the forwarder listens on, and the `PORT` the template sets. The `https:` prefix makes the forwarder terminate TLS with a certificate for its own machine name, which is why HTTPS certificates must be enabled on your tailnet.

![](@/assets/images/tutorials/railway-tailscale-forwarder-variables.png)

Click `Deploy` in the top bar to apply the change.

![](@/assets/images/tutorials/railway-tailscale-forwarder-variables-apply.png)

#### Copy the forwarder domain

Open the [Machines page](https://login.tailscale.com/admin/machines) in the Tailscale admin console. The forwarder appears there on its own once it starts with a valid auth key.

![](@/assets/images/tutorials/tailscale-machines-forwarder.png)

Click the machine to open its page. Under `Machine Details`, copy the `Full domain` value. That is the host you use to open the UI.

![](@/assets/images/tutorials/tailscale-machine-full-domain.png)

#### Open the Studio URL

Take the full domain you copied, add `https://` in front and `:4983` at the end, then open it in your web browser.

```plaintext
https://<full-domain>:4983
```

<Callout type="warning">
Make sure you specify `https://` - opening the URL via `http://` will not work, and some browsers might redirect you to `http://` if you omit the scheme.
</Callout>

Drizzle Studio asks for a passcode on first use.

![](@/assets/images/tutorials/railway-drizzle-studio-passcode-request.png)

Open the Drizzle Studio service in Railway, go to the `Variables` tab, and copy the value of `PASSCODE`. Paste it into the prompt.

![](@/assets/images/tutorials/railway-drizzle-studio-passcode.png)

#### Check the connection

Drizzle Studio opens on the database from `DATABASE_URL`, so there is nothing to connect by hand. It has no tables yet, because you have not applied a schema to it. The next section shows how to create them.

![](@/assets/images/tutorials/drizzle-studio-connected.png)

</Steps>

</Tab>
<Tab>

<Steps>
#### Deploy the Gateway template into the same project

Press the button below to open the Drizzle Gateway template.

**Don't deploy it right away** - make sure to read this step to the end first.

<a
  href="https://railway.com/new/template/drizzle-studio-gateway?referralCode=eobqmj&utm_medium=integration&utm_source=button&utm_campaign=drizzle-studio-gateway"
  target="_blank"
  rel="nofollow noreferrer"
  style="display: inline-block; margin: 16px 0;"
>
  <img src="https://railway.com/button.svg" alt="Deploy on Railway" width="183" height="40" />
</a>

Open the `Deploy to` dropdown and select the project that holds your database. Both services must be in the same project, otherwise Gateway won't be able to reach the database over the private network, since it will be placed on a different private network.

The template comes with the volume mounted at `/app` and two variables, `MASTERPASS` and `PORT`. Drizzle Gateway stores sessions and saved connections in the volume, so without it you lose every connection on each redeploy.

Keep the `${{secret()}}` default for `MASTERPASS`, or type your own password. `PORT` is set to `4983`; leave it as it is, because the forwarder mapping you add later points at the same number. Click `Deploy`.

![](@/assets/images/tutorials/railway-drizzle-gateway-template-config.png)

#### Remove the public domain

Go to the `Settings` tab of the Drizzle Gateway service and find the `Networking` section. If Railway generated a public domain, remove it. Keep the private domain. After this step the UI is reachable only from inside the project, and soon from your tailnet.

![](@/assets/images/tutorials/railway-drizzle-gateway-networking.png)

#### Check MagicDNS and HTTPS certificates

Open the [DNS page](https://login.tailscale.com/admin/dns) in the Tailscale admin console. Both **MagicDNS** and **HTTPS Certificates** must be enabled. Each section offers the opposite action, so a button that reads `Disable MagicDNS...` means MagicDNS is already on. MagicDNS gives the forwarder a stable machine name. HTTPS certificates let the forwarder serve the UI over HTTPS.

![](@/assets/images/tutorials/tailscale-dns-magicdns-https.png)

#### Create a reusable auth key

Go to the [Keys page](https://login.tailscale.com/admin/settings/keys) in the settings menu and click `Generate auth key`. Add a description and turn on `Reusable`. Leave the other settings as they are. A reusable key lets the forwarder register itself again when it starts without existing state.

![](@/assets/images/tutorials/tailscale-generate-auth-key.png)

Click `Generate key`. Copy the key now, because the admin console shows it only once.

![](@/assets/images/tutorials/tailscale-auth-key-created.png)

#### Deploy the Tailscale Forwarder

The Tailscale Forwarder is a small TCP proxy. It joins your tailnet as a machine and forwards ports on that machine to services on the Railway private network. Railway publishes the template, and it runs the `brody192/tailscale-forwarder` image.

<a
  href="https://railway.com/deploy/tailscale-forwarder"
  target="_blank"
  rel="nofollow noreferrer"
  style="display: inline-block; margin: 16px 0;"
>
  <img src="https://railway.com/button.svg" alt="Deploy on Railway" width="183" height="40" />
</a>

Paste your auth key into `TS_AUTHKEY`. Then set `CONNECTION_MAPPING_01` to the database mapping. The format is `[https:]<source port>:<target host>:<target port>`.

```plaintext copy
5432:${{Postgres.RAILWAY_PRIVATE_DOMAIN}}:${{Postgres.PGPORT}}
```

This forwards port `5432` on the forwarder to your database.

![](@/assets/images/tutorials/railway-tailscale-forwarder-template-config.png)

<Callout type="info">
The template setup screen shows only the variables the template declares, and you cannot add new ones there. `CONNECTION_MAPPING_01` is the only mapping you can set now. You will add the second one after the service exists.
</Callout>

#### Deploy and check the logs

Click `Deploy`. The template attaches a volume and sets `TS_EPHEMERAL=false`, so the machine keeps the same identity across redeploys instead of registering a duplicate.

Open the `Deployments` tab and read the deploy logs. Three lines tell you the forwarder started correctly:

- `tsnet starting with hostname "..."` gives the machine name on your tailnet. You need it in a later step.
- `Starting tailscale_fwdr` lists what it parsed, including `ts-ephemeral: false` and the source port, target address and target port of each mapping.
- `listening for connections` confirms the forwarder accepts traffic on that source port.

![](@/assets/images/tutorials/railway-tailscale-forwarder-logs.png)

#### Add the mapping for the UI

Open the `Variables` tab of the Tailscale Forwarder service and add a second mapping. Increase the number for every mapping you add, and keep the source ports unique.

<TableWrapper>

| Variable | Value |
| --- | --- |
| `CONNECTION_MAPPING_02` | `https:4983:${{Drizzle Gateway.RAILWAY_PRIVATE_DOMAIN}}:4983` |

</TableWrapper>

This forwards port `4983` on the forwarder to the UI. Both numbers are `4983`: the port the forwarder listens on, and the `PORT` the template sets. The `https:` prefix makes the forwarder terminate TLS with a certificate for its own machine name, which is why HTTPS certificates must be enabled on your tailnet.

![](@/assets/images/tutorials/railway-tailscale-forwarder-variables.png)

Click `Deploy` in the top bar to apply the change.

![](@/assets/images/tutorials/railway-tailscale-forwarder-variables-apply.png)

#### Copy the forwarder domain

Open the [Machines page](https://login.tailscale.com/admin/machines) in the Tailscale admin console. The forwarder appears there on its own once it starts with a valid auth key.

![](@/assets/images/tutorials/tailscale-machines-forwarder.png)

Click the machine to open its page. Under `Machine Details`, copy the `Full domain` value. That is the host you use to open the UI.

![](@/assets/images/tutorials/tailscale-machine-full-domain.png)

#### Open the Gateway URL

Take the full domain you copied, add `https://` in front and `:4983` at the end, then open it in your web browser.

```plaintext
https://<full-domain>:4983
```

<Callout type="warning">
Make sure you specify `https://` - opening the URL via `http://` will not work, and some browsers might redirect you to `http://` if you omit the scheme.
</Callout>

Drizzle Gateway asks for a passcode on first use. The value it wants is `MASTERPASS`.

![](@/assets/images/tutorials/railway-drizzle-gateway-passcode.png)

Open the Drizzle Gateway service in Railway, go to the `Variables` tab, and copy the value of `MASTERPASS`. Paste it into the prompt.

![](@/assets/images/tutorials/railway-drizzle-gateway-masterpass-variable.png)

#### Add the database connection

Drizzle Gateway starts with no connections. Open the PostgreSQL service in Railway, go to the `Variables` tab, and copy `DATABASE_URL`. It holds the **private** connection string.

![](@/assets/images/tutorials/railway-postgres-database-url.png)

Paste it into the connection form and click `Connect`.

![](@/assets/images/tutorials/drizzle-gateway-add-connection.png)

#### Check the connection

Drizzle Gateway opens on your database. The `public` schema has no tables yet, because you have not applied a schema to it. The next section shows how to create them.

![](@/assets/images/tutorials/drizzle-gateway-connected.png)

</Steps>

</Tab>
</Tabs>

## Next steps

["Connect Drizzle Kit to a private Railway database with Tailscale"](/docs/tutorials/railway-postgres-tailscale-legacy) tutorial points `drizzle-kit` at the same forwarder, so you can generate and apply migrations from your machine, again without public access. Your forwarder is already running, so you only need the last section of that tutorial.

## Troubleshooting

<Callout>
<Fragment slot="collapsed-title">The URL does not open</Fragment>

Open the Studio/Gateway service in Railway, read its deploy logs, and find the line it prints on start. Drizzle Gateway prints:

```plaintext
Drizzle Gateway listening on http://0.0.0.0:4983, store at /app
```

The port on that line must match the target port in `CONNECTION_MAPPING_02`. Both database UIs listen on the port in `PORT`, so if the two disagree, set `PORT` back to `4983` on the service and redeploy.

If the line is missing, the container is not serving at all. The forwarder then reports the target it could not reach:

```plaintext
[ERRO] failed to forward connection source_port=4983
  target_addr="drizzle-studio.railway.internal" target_port=4983
  err="failed to dial target: dial tcp 10.x.x.x:4983: connect: connection refused"
```

`connection refused` means the address is right and nothing is listening on that port. If the log instead shows an empty or literal `${{...}}` target address, the reference variable did not resolve, so check the service name in your mapping.
</Callout>

<Callout>
<Fragment slot="collapsed-title">The web browser shows a certificate warning</Fragment>

The certificate covers the machine's full domain. Open the `Full domain` value from the machine page, not the short name. Check that HTTPS certificates are enabled on the DNS page of the Tailscale admin console.
</Callout>

<Callout>
<Fragment slot="collapsed-title">The forwarder is not in the Machines list</Fragment>

The auth key expired, or a key that was not reusable had already been used. Generate a new reusable key, update `TS_AUTHKEY` on the forwarder service, and redeploy.
</Callout>

<Callout>
<Fragment slot="collapsed-title">The mapping variable is ignored</Fragment>

Confirm the exact variable name on the forwarder service. The template declares `CONNECTION_MAPPING_01`, with a leading zero. Some older guides write `CONNECTION_MAPPING_1`. Use the form the config panel shows you, and keep the numbers unique.
</Callout>


Source: https://orm.drizzle.team/docs/tutorials/railway-studio-tailscale


import Prerequisites from "@mdx/Prerequisites.astro";
import Steps from "@mdx/Steps.astro";
import Callout from "@mdx/Callout.astro";
import Shortcut from "@mdx/Shortcut.astro";
import Tabs from "@mdx/Tabs.astro";
import Tab from "@mdx/Tab.astro";
import TableWrapper from "@mdx/TableWrapper.astro";
import ExternalLinkArrows from "@mdx/ExternalLinkArrows.astro";
import { Image } from "astro:assets";
import diagramLight from "@/assets/images/tutorials/railway-tailscale-browser-diagram-light.png";
import diagramDark from "@/assets/images/tutorials/railway-tailscale-browser-diagram-dark.png";

<style>{`
  .tailscale-diagram-light,
  .tailscale-diagram-dark {
    width: 100%;
    height: auto;
    margin: 16px 0;
  }
  .tailscale-diagram-dark {
    display: none;
  }
  html[class~="dark"] .tailscale-diagram-light {
    display: none;
  }
  html[class~="dark"] .tailscale-diagram-dark {
    display: block;
  }
`}</style>

<ExternalLinkArrows />

Deploy Drizzle Studio or Drizzle Gateway on Railway so that it's reachable only on your tailnet.

<Callout type="info">
If you already run Drizzle Studio or Drizzle Gateway on Railway, follow [Add private access to Drizzle Studio, Gateway or a database on Railway with Tailscale](/docs/tutorials/railway-tailscale-existing-project) instead.
</Callout>

<Prerequisites title="This guide assumes the following:">
  - You have a [Railway](https://driz.link/railway) account.

  - You have a [Tailscale](https://tailscale.com/) account.

  - You have the Tailscale client installed on the machine you work from, and that machine is signed in to your tailnet. You can find the downloads on the [Tailscale website](https://tailscale.com/download).

  - MagicDNS is on in your tailnet, because the address and the machine name depend on it. Tailnets created on or after 2022-10-20 have it on by default. If your tailnet is older, check the [DNS page](https://login.tailscale.com/admin/dns).
</Prerequisites>

## How it works

The template creates two services. One runs the database UI, either Drizzle Studio or Drizzle Gateway. Next to it runs a Tailscale service that joins your tailnet as its own machine and forwards its port to the database UI over Railway's private network. Traffic goes from your device over the tailnet to that machine, and from there to the database UI.

The database UI reaches your database over Railway's private network. The database keeps its `*.railway.internal` domain and stays unreachable from anywhere else.

<Image class="tailscale-diagram-light" src={diagramLight} alt="A web browser reaches the Tailscale service over the tailnet. Inside the Railway private network, the Tailscale service reaches Drizzle Studio or Gateway, which reaches Postgres." />
<Image class="tailscale-diagram-dark" src={diagramDark} alt="A web browser reaches the Tailscale service over the tailnet. Inside the Railway private network, the Tailscale service reaches Drizzle Studio or Gateway, which reaches Postgres." />

## Set up the Railway project

Create a project with a PostgreSQL database that has no public access. If your project already has a database, skip to [Choose Gateway or Studio](#choose-gateway-or-studio).

<Steps>
#### Create a Railway project

Log in to your [Railway dashboard](https://railway.app/dashboard) and click the `New Project` button.

![Railway create menu with Database selected](@/assets/images/tutorials/railway-create-service-menu.png)

#### Provision a PostgreSQL database

On the project canvas, click the `New` button in the top right corner and select `Database` → `PostgreSQL`. You can also use the command palette (<Shortcut mac="⌘ K" other="Ctrl K" />) and search for PostgreSQL.

![Railway database menu with PostgreSQL selected](@/assets/images/tutorials/railway-select-postgres.png)

#### Keep the database on the private network

Click on the PostgreSQL service, go to the `Settings` tab, and find the `Networking` section. Verify that public access is disabled. Under `Private Networking` you will see the private domain of the service, for example `postgres.railway.internal`.

![Postgres Settings tab with no public access and the private domain postgres.railway.internal](@/assets/images/tutorials/railway-postgres-private-networking.png)

</Steps>

## Choose Gateway or Studio

Drizzle has two database UIs, and a Tailscale template for each.

<TableWrapper>

| | Drizzle Studio | Drizzle Gateway |
| --- | --- | --- |
| Databases | One, fixed to the `DATABASE_URL` you set in Railway | Many, you add and edit them in the UI |
| Access | `PASSCODE` generated by the template | `MASTERPASS`, plus passcodes you give to other people |
| Storage | None | A volume holding saved connections |

</TableWrapper>

Pick **Drizzle Studio** when everyone on your tailnet should reach a single database and nothing else.

Pick **Drizzle Gateway** when you need to manage several databases, or give specific people access to specific databases. A Gateway user who knows `MASTERPASS` can add a connection to any database the service can reach.

<Tabs items={['Drizzle Studio', 'Drizzle Gateway']}>
<Tab>

<Steps>
#### Open the template

Press the button below to open the Drizzle Studio with Tailscale template.

**Don't deploy it right away.** Set the variables first.

<a
  href="https://railway.com/new/template/drizzle-studio-with-tailscale?referralCode=eobqmj&utm_medium=integration&utm_source=button&utm_campaign=drizzle-studio-with-tailscale"
  target="_blank"
  rel="nofollow noreferrer"
  style="display: inline-block; margin: 16px 0;"
>
  <img src="https://railway.com/button.svg" alt="Deploy on Railway" width="183" height="40" />
</a>

Open the `Deploy to` dropdown and select the project that holds your database.

![Drizzle Studio with Tailscale deploy form with DATABASE_URL set to the Postgres reference](@/assets/images/tutorials/railway-tailscale-studio-template-form.png)

#### Set the variables

<TableWrapper>

| Variable | What to set |
| --- | --- |
| `DATABASE_URL` | Required. The field is empty. Pick your database service from the list, then pick `DATABASE_URL`. For a service named `Postgres` the field then reads `${{Postgres.DATABASE_URL}}`. |
| `PASSCODE` | Leave the generated value, or type your own passcode |
| `TS_FORWARD_DATABASE` | Optional. If you also want to reach the database itself from your tailnet, for example with `drizzle-kit`, pick `RAILWAY_PRIVATE_DOMAIN` of your database service from the list. Port 5432 on the machine then forwards to your database over Railway's private network. You can also set it later on the Tailscale service's `Variables` tab. |
| `TS_HOSTNAME` | Leave `drizzle-studio`, or pick another name for the machine |

</TableWrapper>

Some variables, such as `TS_HOSTNAME`, are in the collapsed `Pre-Configured Environment Variables` section of the card. Expand it to see or change them.

#### Deploy the template

On each service card, click `Save Config`. Then click `Review and deploy`. Railway opens your project with the template in a side panel. Click `Deploy Template` there.

![Project canvas with the Tailscale and Drizzle Studio services next to Postgres](@/assets/images/tutorials/railway-tailscale-canvas-three-services.png)

#### Sign in from the deploy log

Open the `Tailscale` service, then its `Deployments` tab, and read the deploy log. The last lines of the log hold a sign-in link:

```plaintext
This service is not on your tailnet yet. Open this link and sign in
with the account that owns your tailnet:
  https://login.tailscale.com/a/xxxxxxxxxxxx
```

Open the link and sign in. Anyone who opens that link first gets this machine on their tailnet, so do not forward it. The log is visible only to members of your Railway project.

![Tailscale deploy log with the sign-in message and a hidden link](@/assets/images/tutorials/railway-tailscale-signin-log.png)

If your tailnet requires device approval, the log says so and the machine waits until you approve it on the [Machines page](https://login.tailscale.com/admin/machines).

#### Read the address from the deploy log

A few seconds after you sign in, the same log prints where to go:

```plaintext
joined tailnet: example.com
4983: ready
open https://drizzle-studio.example-com.ts.net from any device on your tailnet
```

![Tailscale deploy log with the joined tailnet, open and 4983 ready lines](@/assets/images/tutorials/railway-tailscale-open-log.png)

Check that the tailnet name is yours. If it is not, someone else opened the sign-in link first, and their tailnet can now reach this service. To take the service back:

1. On the project canvas, click the volume under the Tailscale service, open its `Settings` tab, and click `Wipe volume`.
2. Type the confirmation text and click `Wipe`. Railway deletes the machine's key and redeploys the service.
3. Open the sign-in link from the new deploy log yourself.
4. Change `PASSCODE` on the Drizzle Studio service. If you set `TS_FORWARD_DATABASE`, also change the database user's password.

If your tailnet already has a machine with that name, the machine name ends in `-1`, `-2` and so on. Use the address the log prints.

If HTTPS certificates are off in your tailnet, the address starts with `http://` and ends in `:4983` instead. Tailscale encrypts the connection either way. To get the `https://` address, enable `HTTPS Certificates` on the [DNS page](https://login.tailscale.com/admin/dns).

If you set `TS_FORWARD_DATABASE`, the log also prints `5432: ready`.

#### Open Drizzle Studio

Open that address in your web browser. On the first `https://` visit, the Tailscale service still fetches its certificate, so the page can fail or load slowly for about two minutes. If that happens, reload the page.

Drizzle Studio asks for a passcode on first use.

![Drizzle Studio passcode prompt with a hint to check PASSCODE in Railway container variables](@/assets/images/tutorials/railway-drizzle-studio-passcode-request.png)

Open the `Drizzle Studio` service in Railway, go to the `Variables` tab, and copy the value of `PASSCODE`. Paste it into the prompt.

![Drizzle Studio Variables tab with PASSCODE marked](@/assets/images/tutorials/railway-drizzle-studio-passcode.png)

#### Check the connection

Drizzle Studio opens on the database from `DATABASE_URL`.

![Drizzle Studio on the tailnet with the posts table open](@/assets/images/tutorials/drizzle-studio-on-tailnet.png)

</Steps>

</Tab>
<Tab>

<Steps>
#### Open the template

Press the button below to open the Drizzle Gateway with Tailscale template.

**Don't deploy it right away.** Set the variables first.

<a
  href="https://railway.com/new/template/drizzle-gateway-with-tailscale?referralCode=eobqmj&utm_medium=integration&utm_source=button&utm_campaign=drizzle-gateway-with-tailscale"
  target="_blank"
  rel="nofollow noreferrer"
  style="display: inline-block; margin: 16px 0;"
>
  <img src="https://railway.com/button.svg" alt="Deploy on Railway" width="183" height="40" />
</a>

Open the `Deploy to` dropdown and select the project that holds your database.

![Drizzle Gateway with Tailscale deploy form with Postgres references in TS_FORWARD_DATABASE and DATABASE_URL_Postgres](@/assets/images/tutorials/railway-tailscale-gateway-template-form.png)

#### Set the variables

<TableWrapper>

| Variable | What to set |
| --- | --- |
| `MASTERPASS` | Leave the generated value, or type your own password |
| `DATABASE_URL_Postgres` | Optional. Pick `DATABASE_URL` of your database service from the list. Drizzle Gateway then opens with that connection saved. Leave the field empty to add connections in Drizzle Gateway later. |
| `TS_FORWARD_DATABASE` | Optional. If you also want to reach the database itself from your tailnet, for example with `drizzle-kit`, pick `RAILWAY_PRIVATE_DOMAIN` of your database service from the list. Port 5432 on the machine then forwards to your database over Railway's private network. You can also set it later on the Tailscale service's `Variables` tab. |
| `TS_HOSTNAME` | Leave `drizzle-gateway`, or pick another name for the machine |

</TableWrapper>

Some variables, such as `TS_HOSTNAME`, are in the collapsed `Pre-Configured Environment Variables` section of the card. Expand it to see or change them.

<Callout type="info">
`DATABASE_URL_Postgres` creates a connection the first time the service starts against an empty volume. Adding it later has no effect, because the volume already holds a store by then. Add later databases through the UI.
</Callout>

#### Deploy the template

On each service card, click `Save Config`. Then click `Review and deploy`. Railway opens your project with the template in a side panel. Click `Deploy Template` there.

#### Sign in from the deploy log

Open the `Tailscale` service, then its `Deployments` tab, and read the deploy log. The last lines of the log hold a sign-in link:

```plaintext
This service is not on your tailnet yet. Open this link and sign in
with the account that owns your tailnet:
  https://login.tailscale.com/a/xxxxxxxxxxxx
```

Open the link and sign in. Anyone who opens that link first gets this machine on their tailnet, so do not forward it. The log is visible only to members of your Railway project.

![Tailscale deploy log with the sign-in message and a hidden link](@/assets/images/tutorials/railway-tailscale-signin-log.png)

If your tailnet requires device approval, the log says so and the machine waits until you approve it on the [Machines page](https://login.tailscale.com/admin/machines).

#### Read the address from the deploy log

A few seconds after you sign in, the same log prints where to go:

```plaintext
joined tailnet: example.com
4983: ready
open https://drizzle-gateway.example-com.ts.net from any device on your tailnet
```

![Tailscale deploy log with the joined tailnet, open and 4983 ready lines](@/assets/images/tutorials/railway-tailscale-open-log.png)

Check that the tailnet name is yours. If it is not, someone else opened the sign-in link first, and their tailnet can now reach this service. To take the service back:

1. On the project canvas, click the volume under the Tailscale service, open its `Settings` tab, and click `Wipe volume`.
2. Type the confirmation text and click `Wipe`. Railway deletes the machine's key and redeploys the service.
3. Open the sign-in link from the new deploy log yourself.
4. Change `MASTERPASS` on the Drizzle Gateway service. If you set `TS_FORWARD_DATABASE`, also change the database user's password.

If your tailnet already has a machine with that name, the machine name ends in `-1`, `-2` and so on. Use the address the log prints.

If HTTPS certificates are off in your tailnet, the address starts with `http://` and ends in `:4983` instead. Tailscale encrypts the connection either way. To get the `https://` address, enable `HTTPS Certificates` on the [DNS page](https://login.tailscale.com/admin/dns).

If you set `TS_FORWARD_DATABASE`, the log also prints `5432: ready`.

#### Open Drizzle Gateway

Open that address in your web browser. On the first `https://` visit, the Tailscale service still fetches its certificate, so the page can fail or load slowly for about two minutes. If that happens, reload the page.

Drizzle Gateway asks for a passcode on first use.

![Drizzle Gateway passcode prompt with an empty field and a Continue button](@/assets/images/tutorials/railway-drizzle-gateway-passcode.png)

Open the `Drizzle Gateway` service in Railway, go to the `Variables` tab, and copy the value of `MASTERPASS`. Paste it into the prompt.

![Drizzle Gateway Variables tab with MASTERPASS](@/assets/images/tutorials/railway-drizzle-gateway-masterpass-variable.png)

#### Check the connection

Drizzle Gateway opens with the connection you picked for `DATABASE_URL_Postgres` on the deploy form. If you left that field empty, Drizzle Gateway opens with the connection form. Copy `DATABASE_URL` from your database service's `Variables` tab and paste it into a new connection.

![Drizzle Gateway on the tailnet with the Postgres connection listed](@/assets/images/tutorials/drizzle-gateway-on-tailnet.png)

</Steps>

</Tab>
</Tabs>

## Use other ports

By default, `TS_FORWARD_BROWSER` uses port 4983 and `TS_FORWARD_DATABASE` uses port 5432, on the machine and on the service. To use other ports, write the value in the form `[port:]host[:port]`:

<TableWrapper>

| Value | Port on the machine | Port on the service |
| --- | --- | --- |
| `host` | The default port | The default port |
| `host:port` | `port` | `port` |
| `source_port:host:target_port` | `source_port` | `target_port` |

</TableWrapper>

For example, `5433:${{Postgres.RAILWAY_PRIVATE_DOMAIN}}:5432` forwards port 5433 on the machine to port 5432 of the database service.

If the port on the machine for `TS_FORWARD_BROWSER` is not 4983, an `http://` address in the log ends in that port.

## Disable key expiry

A machine that joined by signing in has its key expire on your tailnet's schedule, 180 days by default. When that happens, the Tailscale service prints a new sign-in link and waits. The address is unreachable until you click it.

To avoid that, open the [Machines page](https://login.tailscale.com/admin/machines) once, find the machine, open the menu at the far right of its row, and choose `Disable key expiry`.

![Tailscale Machines page menu with Disable key expiry](@/assets/images/tutorials/tailscale-machines-disable-key-expiry.png)

<Callout type="info">
If you automate deployments and want no sign-in at all, set `TS_AUTHKEY` on the Tailscale service:

- For an auth key, set `TS_AUTHKEY` to the key.
- For an OAuth client secret, set `TS_AUTHKEY` to the secret with `?ephemeral=false&preauthorized=true` appended. Without that suffix, Tailscale removes the machine when it disconnects, and the machine waits for approval before it joins. Also set `TS_TAGS` to a tag you own, for example `tag:drizzle`. A tagged machine never has its key expire.

The Tailscale service reads `TS_AUTHKEY` only before the machine joins. If the machine has already joined, remove the machine and wipe the volume first.
</Callout>

## Troubleshoot the Tailscale setup

Open the entry that matches what you see.

<Callout>
<Fragment slot="collapsed-title">A new sign-in link appeared in the log</Fragment>

The service restarted, for example after the key expired or the machine was removed. Open the newest link. The link works once.
</Callout>

<Callout>
<Fragment slot="collapsed-title">The log says the machine is waiting for approval</Fragment>

Your tailnet has device approval turned on. Open the [Machines page](https://login.tailscale.com/admin/machines) and approve it.
</Callout>

<Callout>
<Fragment slot="collapsed-title">Studio opens but shows no tables</Fragment>

A new database has no tables until you apply a schema. Follow [Run Drizzle Kit against a private Railway database over Tailscale](/docs/tutorials/railway-postgres-tailscale) to create them. If your database already has tables, check `DATABASE_URL` on the Drizzle Studio service's `Variables` tab. It can point at a service outside this project, or hold a connection string that does not match your database. Set it to `${{Postgres.DATABASE_URL}}`, with your database service name in place of `Postgres`, and click `Deploy`.
</Callout>

<Callout>
<Fragment slot="collapsed-title">The address does not open</Fragment>

Check these causes in order:

- Your device is signed in to another tailnet. Run `tailscale status` on your device and compare its tailnet with the one the log named.
- The log printed an `http://` address. Use that exact address with the port, because `https://` works only when HTTPS certificates are on in your tailnet.
- The Tailscale service is still fetching its certificate on the first `https://` visit. Wait about two minutes and reload the page.
- MagicDNS is off, so the address does not resolve. Enable MagicDNS on the [DNS page](https://login.tailscale.com/admin/dns).
</Callout>

<Callout>
<Fragment slot="collapsed-title">It worked for months and then stopped</Fragment>

The machine's key expired. Open the Tailscale service's deploy log; it is printing a fresh sign-in link. Click it, then disable key expiry on the machine so it does not happen again.
</Callout>

<Callout>
<Fragment slot="collapsed-title">The machine name gained a `-1` suffix</Fragment>

Your tailnet already had a machine with this name, for example from an earlier deploy. Tailscale keeps the suffix. If you want the short name, rename the machine on the Machines page. Otherwise, use the address the log prints.
</Callout>

<Callout>
<Fragment slot="collapsed-title">The log prints no `open` line</Fragment>

`TS_FORWARD_BROWSER` is empty, or the Tailscale service skipped it. A reference resolves to an empty value when it names a service that was not in the project when the template deployed. A skipped variable has its own line in the log, and the next entry explains that line. Open the Tailscale service's `Variables` tab, set `TS_FORWARD_BROWSER` to `${{"Drizzle Gateway".RAILWAY_PRIVATE_DOMAIN}}` (with `"Drizzle Studio"` for Studio), and click `Deploy` in the top bar.
</Callout>

<Callout>
<Fragment slot="collapsed-title">The log prints a line that ends in `skipped`</Fragment>

The line starts with the variable name, then gives the reason:

- `does not match [port:]host[:port]`: the value has more than two colons.
- `has an empty target host`: the value has a port but no host. A reference that names a service outside your project resolves to an empty host.
- `still contains a Railway reference that did not resolve`: Railway did not replace the reference. Check the service name inside it.
- `has a port outside 1-65535`: a port is not a number from 1 to 65535.
- `reuses port`: an earlier forward already uses that port on the machine.
- `uses port 443, which the https listener owns`: pick another port on the machine. The address of the database UI already uses 443 when HTTPS certificates are on.

Fix the value on the Tailscale service's `Variables` tab and click `Deploy` in the top bar.
</Callout>

## Next steps

- [Run Drizzle Kit against a private Railway database over Tailscale](/docs/tutorials/railway-postgres-tailscale) to run migrations over your tailnet.
- [Drizzle migrations fundamentals](/docs/migrations) to choose how to apply schema changes.


Source: https://orm.drizzle.team/docs/tutorials/railway-tailscale-existing-project


import Prerequisites from "@mdx/Prerequisites.astro";
import Steps from "@mdx/Steps.astro";
import Callout from "@mdx/Callout.astro";
import Tabs from "@mdx/Tabs.astro";
import Tab from "@mdx/Tab.astro";
import TableWrapper from "@mdx/TableWrapper.astro";
import ExternalLinkArrows from "@mdx/ExternalLinkArrows.astro";

<ExternalLinkArrows />

Railway's private network is reachable only from services inside the project. To reach Drizzle Studio or Drizzle Gateway from your machine, the service needs a public domain, and a public domain is open to everyone on the internet.

This guide adds a Tailscale service to a project that already runs Drizzle Studio or Drizzle Gateway. The database UI then has an address that only devices on your tailnet can open, and you can remove its public domain. The database itself can get the same private address, so that `drizzle-kit` or a [desktop database client](https://www.rubberboots.app/) on your machine connects to it while public networking stays off.

<Callout type="info" highlighted>
If you didn't deploy Drizzle Studio or Gateway yet, follow [Deploy Drizzle Studio or Gateway on Railway with private access over Tailscale](/docs/tutorials/railway-studio-tailscale).
</Callout>

<Prerequisites title="This guide assumes the following:">
  - Your project runs a service named `Drizzle Studio` or `Drizzle Gateway`.

  - You have a [Tailscale](https://tailscale.com/) account.

  - You have the Tailscale client installed on the machine you work from, and that machine is signed in to your tailnet. You can find the downloads on the [Tailscale website](https://tailscale.com/download).

  - MagicDNS is on in your tailnet, because the address and the machine name depend on it. Tailnets created on or after 2022-10-20 have it on by default. If your tailnet is older, check the [DNS page](https://login.tailscale.com/admin/dns).
</Prerequisites>

## Add the Tailscale service

Pick the tab for your database UI.

<Tabs items={['Drizzle Studio', 'Drizzle Gateway']}>
<Tab>

<Steps>
#### Open the template

Press the button below to open the Tailscale for Drizzle template.

**Don't deploy it right away.** Set the variables first.

<a
  href="https://railway.com/new/template/tailscale-for-drizzle?referralCode=eobqmj&utm_medium=integration&utm_source=button&utm_campaign=tailscale-for-drizzle"
  target="_blank"
  rel="nofollow noreferrer"
  style="display: inline-block; margin: 16px 0;"
>
  <img src="https://railway.com/button.svg" alt="Deploy on Railway" width="183" height="40" />
</a>

Open the `Deploy to` dropdown and select the project that holds your Drizzle Studio service.

![Tailscale for Drizzle deploy form with TS_FORWARD_BROWSER set to a reference to the Drizzle Studio service](@/assets/images/tutorials/railway-tailscale-sidecar-studio-form.png)

#### Set the variables

<TableWrapper>

| Variable | What to set |
| --- | --- |
| `TS_FORWARD_BROWSER` | The field is empty. Pick `RAILWAY_PRIVATE_DOMAIN` of your Studio service from the list. The field then reads `${{"Drizzle Studio".RAILWAY_PRIVATE_DOMAIN}}`. |
| `TS_FORWARD_DATABASE` | Optional. If you also want to reach the database itself from your tailnet, for example with `drizzle-kit`, pick `RAILWAY_PRIVATE_DOMAIN` of your database service from the list. Port 5432 on the machine then forwards to your database over Railway's private network. You can also set it later on the Tailscale service's `Variables` tab. |
| `TS_HOSTNAME` | Change it to `drizzle-studio`, or pick another name for the machine |

</TableWrapper>

Some variables, such as `TS_HOSTNAME`, are in the collapsed `Pre-Configured Environment Variables` section of the card. Expand it to see or change them.

#### Deploy the template

On the service card, click `Save Config`. Then click `Review and deploy`. Railway opens your project with the template in a side panel. Click `Deploy Template` there.

#### Remove the public domain

This step is optional. Without it, the database UI stays reachable on its public domain as well as on your tailnet.

Go to the `Settings` tab of the Drizzle Studio service and find the `Networking` section. If Railway generated a public domain, remove it. Keep the private domain.

![Drizzle Studio Settings tab with the delete button of the public domain marked](@/assets/images/tutorials/railway-drizzle-studio-remove-public-domain.png)

#### Sign in from the deploy log

Open the `Tailscale` service, then its `Deployments` tab, and read the deploy log. The last lines of the log hold a sign-in link:

```plaintext
This service is not on your tailnet yet. Open this link and sign in
with the account that owns your tailnet:
  https://login.tailscale.com/a/xxxxxxxxxxxx
```

Open the link and sign in. Anyone who opens that link first gets this machine on their tailnet, so do not forward it. The log is visible only to members of your Railway project.

![Tailscale deploy log with the sign-in message and a hidden link](@/assets/images/tutorials/railway-tailscale-signin-log.png)

If your tailnet requires device approval, the log says so and the machine waits until you approve it on the [Machines page](https://login.tailscale.com/admin/machines).

#### Read the address from the deploy log

A few seconds after you sign in, the same log prints where to go:

```plaintext
joined tailnet: example.com
4983: ready
open https://drizzle-studio.example-com.ts.net from any device on your tailnet
```

![Tailscale deploy log with the joined tailnet, open and 4983 ready lines](@/assets/images/tutorials/railway-tailscale-open-log.png)

Check that the tailnet name is yours. If it is not, someone else opened the sign-in link first, and their tailnet can now reach this service. To take the service back:

1. On the project canvas, click the volume under the Tailscale service, open its `Settings` tab, and click `Wipe volume`.
2. Type the confirmation text and click `Wipe`. Railway deletes the machine's key and redeploys the service.
3. Open the sign-in link from the new deploy log yourself.
4. Change `PASSCODE` on your Drizzle Studio service. If you set `TS_FORWARD_DATABASE`, also change the database user's password.

If your tailnet already has a machine with that name, the machine name ends in `-1`, `-2` and so on. Use the address the log prints.

If HTTPS certificates are off in your tailnet, the address starts with `http://` and ends in `:4983` instead.

If you set `TS_FORWARD_DATABASE`, the log also prints `5432: ready`.

#### Open Drizzle Studio

Open that address in your web browser. On the first `https://` visit, the Tailscale service still fetches its certificate, so the page can fail or load slowly for about two minutes. If that happens, reload the page.

Drizzle Studio asks for a passcode on first use.

![Drizzle Studio passcode prompt with a hint to check PASSCODE in Railway container variables](@/assets/images/tutorials/railway-drizzle-studio-passcode-request.png)

Open your Drizzle Studio service in Railway, go to the `Variables` tab, and copy the value of `PASSCODE`. Paste it into the prompt.

#### Check the connection

Drizzle Studio opens on the database from `DATABASE_URL`, as it did on the public domain.

![Drizzle Studio on the tailnet with the posts table open](@/assets/images/tutorials/drizzle-studio-on-tailnet.png)

</Steps>

</Tab>
<Tab>

<Steps>
#### Open the template

Press the button below to open the Tailscale for Drizzle template.

**Don't deploy it right away.** Set the variables first.

<a
  href="https://railway.com/new/template/tailscale-for-drizzle?referralCode=eobqmj&utm_medium=integration&utm_source=button&utm_campaign=tailscale-for-drizzle"
  target="_blank"
  rel="nofollow noreferrer"
  style="display: inline-block; margin: 16px 0;"
>
  <img src="https://railway.com/button.svg" alt="Deploy on Railway" width="183" height="40" />
</a>

Open the `Deploy to` dropdown and select the project that holds your Drizzle Gateway service.

![Tailscale for Drizzle deploy form with TS_FORWARD_BROWSER set to a reference to the Drizzle Gateway service](@/assets/images/tutorials/railway-tailscale-sidecar-gateway-form.png)

#### Set the variables

<TableWrapper>

| Variable | What to set |
| --- | --- |
| `TS_FORWARD_BROWSER` | The field is empty. Pick `RAILWAY_PRIVATE_DOMAIN` of your Gateway service from the list. The field then reads `${{"Drizzle Gateway".RAILWAY_PRIVATE_DOMAIN}}`. |
| `TS_FORWARD_DATABASE` | Optional. If you also want to reach the database itself from your tailnet, for example with `drizzle-kit`, pick `RAILWAY_PRIVATE_DOMAIN` of your database service from the list. Port 5432 on the machine then forwards to your database over Railway's private network. You can also set it later on the Tailscale service's `Variables` tab. |
| `TS_HOSTNAME` | Change it to `drizzle-gateway`, or pick another name for the machine |

</TableWrapper>

Some variables, such as `TS_HOSTNAME`, are in the collapsed `Pre-Configured Environment Variables` section of the card. Expand it to see or change them.

#### Deploy the template

On the service card, click `Save Config`. Then click `Review and deploy`. Railway opens your project with the template in a side panel. Click `Deploy Template` there.

#### Remove the public domain

This step is optional. Without it, the database UI stays reachable on its public domain as well as on your tailnet.

Go to the `Settings` tab of the Drizzle Gateway service and find the `Networking` section. If Railway generated a public domain, remove it. Keep the private domain.

![Drizzle Gateway Settings tab with the delete button of the public domain marked](@/assets/images/tutorials/railway-drizzle-gateway-networking.png)

#### Sign in from the deploy log

Open the `Tailscale` service, then its `Deployments` tab, and read the deploy log. The last lines of the log hold a sign-in link:

```plaintext
This service is not on your tailnet yet. Open this link and sign in
with the account that owns your tailnet:
  https://login.tailscale.com/a/xxxxxxxxxxxx
```

Open the link and sign in. Anyone who opens that link first gets this machine on their tailnet, so do not forward it. The log is visible only to members of your Railway project.

![Tailscale deploy log with the sign-in message and a hidden link](@/assets/images/tutorials/railway-tailscale-signin-log.png)

If your tailnet requires device approval, the log says so and the machine waits until you approve it on the [Machines page](https://login.tailscale.com/admin/machines).

#### Read the address from the deploy log

A few seconds after you sign in, the same log prints where to go:

```plaintext
joined tailnet: example.com
4983: ready
open https://drizzle-gateway.example-com.ts.net from any device on your tailnet
```

![Tailscale deploy log with the joined tailnet, open and 4983 ready lines](@/assets/images/tutorials/railway-tailscale-open-log.png)

Check that the tailnet name is yours. If it is not, someone else opened the sign-in link first, and their tailnet can now reach this service. To take the service back:

1. On the project canvas, click the volume under the Tailscale service, open its `Settings` tab, and click `Wipe volume`.
2. Type the confirmation text and click `Wipe`. Railway deletes the machine's key and redeploys the service.
3. Open the sign-in link from the new deploy log yourself.
4. Change `MASTERPASS` on your Drizzle Gateway service. If you set `TS_FORWARD_DATABASE`, also change the database user's password.

If your tailnet already has a machine with that name, the machine name ends in `-1`, `-2` and so on. Use the address the log prints.

If HTTPS certificates are off in your tailnet, the address starts with `http://` and ends in `:4983` instead.

If you set `TS_FORWARD_DATABASE`, the log also prints `5432: ready`.

#### Open Drizzle Gateway

Open that address in your web browser. On the first `https://` visit, the Tailscale service still fetches its certificate, so the page can fail or load slowly for about two minutes. If that happens, reload the page.

Drizzle Gateway asks for a passcode on first use.

![Drizzle Gateway passcode prompt with an empty field and a Continue button](@/assets/images/tutorials/railway-drizzle-gateway-passcode.png)

Open your Drizzle Gateway service in Railway, go to the `Variables` tab, and copy the value of `MASTERPASS`. Paste it into the prompt.

#### Check the connection

Drizzle Gateway opens with the connections you saved before.

![Drizzle Gateway on the tailnet with the Postgres connection listed](@/assets/images/tutorials/drizzle-gateway-on-tailnet.png)

</Steps>

</Tab>
</Tabs>

## Use other ports

By default, `TS_FORWARD_BROWSER` uses port 4983 and `TS_FORWARD_DATABASE` uses port 5432, on the machine and on the service. To use other ports, write the value in the form `[port:]host[:port]`:

<TableWrapper>

| Value | Port on the machine | Port on the service |
| --- | --- | --- |
| `host` | The default port | The default port |
| `host:port` | `port` | `port` |
| `source_port:host:target_port` | `source_port` | `target_port` |

</TableWrapper>

For example, `5433:${{Postgres.RAILWAY_PRIVATE_DOMAIN}}:5432` forwards port 5433 on the machine to port 5432 of the database service.

If the port on the machine for `TS_FORWARD_BROWSER` is not 4983, an `http://` address in the log ends in that port.

## Disable key expiry

A machine that joined by signing in has its key expire on your tailnet's schedule, 180 days by default. When that happens, the Tailscale service prints a new sign-in link and waits. The address is unreachable until you click it.

To avoid that, open the [Machines page](https://login.tailscale.com/admin/machines) once, find the machine, open the menu at the far right of its row, and choose `Disable key expiry`.

![Tailscale Machines page menu with Disable key expiry](@/assets/images/tutorials/tailscale-machines-disable-key-expiry.png)

<Callout type="info">
If you automate deployments and want no sign-in at all, set `TS_AUTHKEY` on the Tailscale service:

- For an auth key, set `TS_AUTHKEY` to the key.
- For an OAuth client secret, set `TS_AUTHKEY` to the secret with `?ephemeral=false&preauthorized=true` appended. Without that suffix, Tailscale removes the machine when it disconnects, and the machine waits for approval before it joins. Also set `TS_TAGS` to a tag you own, for example `tag:drizzle`. A tagged machine never has its key expire.

The Tailscale service reads `TS_AUTHKEY` only before the machine joins. If the machine has already joined, remove the machine and wipe the volume first.
</Callout>

## Troubleshoot the Tailscale setup

Open the entry that matches what you see.

<Callout>
<Fragment slot="collapsed-title">The log prints no `open` line</Fragment>

`TS_FORWARD_BROWSER` is empty, or the Tailscale service skipped it. A reference resolves to an empty value when it names a service that was not in the project when the template deployed. A skipped variable has its own line in the log, and the next entry explains that line. Open the Tailscale service's `Variables` tab, set `TS_FORWARD_BROWSER` to `${{"Drizzle Gateway".RAILWAY_PRIVATE_DOMAIN}}` (with `"Drizzle Studio"` for Studio), and click `Deploy` in the top bar.
</Callout>

<Callout>
<Fragment slot="collapsed-title">The log prints a line that ends in `skipped`</Fragment>

The line starts with the variable name, then gives the reason:

- `does not match [port:]host[:port]`: the value has more than two colons.
- `has an empty target host`: the value has a port but no host. A reference that names a service outside your project resolves to an empty host.
- `still contains a Railway reference that did not resolve`: Railway did not replace the reference. Check the service name inside it.
- `has a port outside 1-65535`: a port is not a number from 1 to 65535.
- `reuses port`: an earlier forward already uses that port on the machine.
- `uses port 443, which the https listener owns`: pick another port on the machine. The address of the database UI already uses 443 when HTTPS certificates are on.

Fix the value on the Tailscale service's `Variables` tab and click `Deploy` in the top bar.
</Callout>

<Callout>
<Fragment slot="collapsed-title">A new sign-in link appeared in the log</Fragment>

The service restarted, for example after the key expired or the machine was removed. Open the newest link. The link works once.
</Callout>

<Callout>
<Fragment slot="collapsed-title">The log says the machine is waiting for approval</Fragment>

Your tailnet has device approval turned on. Open the [Machines page](https://login.tailscale.com/admin/machines) and approve it.
</Callout>

<Callout>
<Fragment slot="collapsed-title">The address does not open</Fragment>

Check these causes in order:

- Your device is signed in to another tailnet. Run `tailscale status` on your device and compare its tailnet with the one the log named.
- The log printed an `http://` address. Use that exact address with the port, because `https://` works only when HTTPS certificates are on in your tailnet.
- The Tailscale service is still fetching its certificate on the first `https://` visit. Wait about two minutes and reload the page.
- MagicDNS is off, so the address does not resolve. Enable MagicDNS on the [DNS page](https://login.tailscale.com/admin/dns).
</Callout>

<Callout>
<Fragment slot="collapsed-title">It worked for months and then stopped</Fragment>

The machine's key expired. Open the Tailscale service's deploy log; it is printing a fresh sign-in link. Click it, then disable key expiry on the machine so it does not happen again.
</Callout>

<Callout>
<Fragment slot="collapsed-title">The machine name gained a `-1` suffix</Fragment>

Your tailnet already had a machine with this name, for example from an earlier deploy. Tailscale keeps the suffix. If you want the short name, rename the machine on the Machines page. Otherwise, use the address the log prints.
</Callout>

## Next steps

- If you set `TS_FORWARD_DATABASE`, [connect Drizzle Kit to the database](/docs/tutorials/railway-postgres-tailscale) to run migrations over your tailnet.
- [Drizzle migrations fundamentals](/docs/migrations) to choose how to apply schema changes.


Source: https://orm.drizzle.team/docs/typebox-legacy

import Npm from '@mdx/Npm.astro';
import Callout from '@mdx/Callout.astro';

<Callout type="error">
Starting from `drizzle-orm@1.0.0-beta.15`, `drizzle-typebox` has been deprecated in favor of first-class schema generation support within Drizzle ORM itself

You can still use `drizzle-typebox` package but all new update will be added to Drizzle ORM directly

This version of `typebox` is legacy by using `@sinclair/typebox` package
</Callout>

# typebox-legacy

### Install the dependencies
<Npm>
drizzle-orm@rc @sinclair/typebox
</Npm>

### Select schema

Defines the shape of data queried from the database - can be used to validate API responses.

```ts copy
import { pgTable, text, integer } from 'drizzle-orm/pg-core';
import { createSelectSchema } from 'drizzle-orm/typebox-legacy';
import { Value } from '@sinclair/typebox/value';

const users = pgTable('users', {
  id: integer().generatedAlwaysAsIdentity().primaryKey(),
  name: text().notNull(),
  age: integer().notNull()
});

const userSelectSchema = createSelectSchema(users);

const rows = await db.select({ id: users.id, name: users.name }).from(users).limit(1);
const parsed: { id: number; name: string; age: number } = Value.Parse(userSelectSchema, rows[0]); // Error: `age` is not returned in the above query

const rows = await db.select().from(users).limit(1);
const parsed: { id: number; name: string; age: number } = Value.Parse(userSelectSchema, rows[0]); // Will parse successfully
```

Views and enums are also supported.

```ts copy
import { pgEnum } from 'drizzle-orm/pg-core';
import { createSelectSchema } from 'drizzle-orm/typebox-legacy';
import { Value } from '@sinclair/typebox/value';

const roles = pgEnum('roles', ['admin', 'basic']);
const rolesSchema = createSelectSchema(roles);
const parsed: 'admin' | 'basic' = Value.Parse(rolesSchema, ...);

const usersView = pgView('users_view').as((qb) => qb.select().from(users).where(gt(users.age, 18)));
const usersViewSchema = createSelectSchema(usersView);
const parsed: { id: number; name: string; age: number } = Value.Parse(usersViewSchema, ...);
```

### Insert schema

Defines the shape of data to be inserted into the database - can be used to validate API requests.

```ts copy
import { pgTable, text, integer } from 'drizzle-orm/pg-core';
import { createInsertSchema } from 'drizzle-orm/typebox-legacy';
import { Value } from '@sinclair/typebox/value';

const users = pgTable('users', {
  id: integer().generatedAlwaysAsIdentity().primaryKey(),
  name: text().notNull(),
  age: integer().notNull()
});

const userInsertSchema = createInsertSchema(users);

const user = { name: 'John' };
const parsed: { name: string, age: number } = Value.Parse(userInsertSchema, user); // Error: `age` is not defined

const user = { name: 'Jane', age: 30 };
const parsed: { name: string, age: number } = Value.Parse(userInsertSchema, user); // Will parse successfully
await db.insert(users).values(parsed);
```

### Update schema

Defines the shape of data to be updated in the database - can be used to validate API requests.

```ts copy
import { pgTable, text, integer } from 'drizzle-orm/pg-core';
import { createUpdateSchema } from 'drizzle-orm/typebox-legacy';
import { Value } from '@sinclair/typebox/value';

const users = pgTable('users', {
  id: integer().generatedAlwaysAsIdentity().primaryKey(),
  name: text().notNull(),
  age: integer().notNull()
});

const userUpdateSchema = createUpdateSchema(users);

const user = { id: 5, name: 'John' };
const parsed: { name?: string | undefined, age?: number | undefined } = Value.Parse(userUpdateSchema, user); // Error: `id` is a generated column, it can't be updated

const user = { age: 35 };
const parsed: { name?: string | undefined, age?: number | undefined } = Value.Parse(userUpdateSchema, user); // Will parse successfully
await db.update(users).set(parsed).where(eq(users.name, 'Jane'));
```

### Refinements

Each create schema function accepts an additional optional parameter that you can used to extend, modify or completely overwite a field's schema. Defining a callback function will extend or modify while providing a Typebox schema will overwrite it.

```ts copy
import { pgTable, text, integer, json } from 'drizzle-orm/pg-core';
import { createSelectSchema } from 'drizzle-orm/typebox-legacy';
import { Type } from '@sinclair/typebox';
import { Value } from '@sinclair/typebox/value';

const users = pgTable('users', {
  id: integer().generatedAlwaysAsIdentity().primaryKey(),
  name: text().notNull(),
  bio: text(),
  preferences: json()
});

const userSelectSchema = createSelectSchema(users, {
  name: (schema) => Type.String({ ...schema, maxLength: 20 }), // Extends schema
  bio: (schema) => Type.String({ ...schema, maxLength: 1000 }), // Extends schema before becoming nullable/optional
  preferences: Type.Object({ theme: Type.String() }) // Overwrites the field, including its nullability
});

const parsed: {
  id: number;
  name: string,
  bio?: string | undefined;
  preferences: {
    theme: string;
  };
} = Value.Parse(userSelectSchema, ...);
```

### Factory functions

For more advanced use cases, you can use the `createSchemaFactory` function.

**Use case: Using an extended Typebox instance**

```ts copy
import { pgTable, text, integer } from 'drizzle-orm/pg-core';
import { createSchemaFactory } from 'drizzle-orm/typebox';
import { t } from 'elysia'; // Extended Typebox instance

const users = pgTable('users', {
  id: integer().generatedAlwaysAsIdentity().primaryKey(),
  name: text().notNull(),
  age: integer().notNull()
});

const { createInsertSchema } = createSchemaFactory({ typeboxInstance: t });

const userInsertSchema = createInsertSchema(users, {
  // We can now use the extended instance
  name: (schema) => t.Number({ ...schema }, { error: '`name` must be a string' })
});
```

### Data type reference

```ts
pg.boolean();

mysql.boolean();

sqlite.integer({ mode: 'boolean' });

// Schema
Type.Boolean();
```

```ts
pg.date({ mode: 'date' });
pg.timestamp({ mode: 'date' });

mysql.date({ mode: 'date' });
mysql.datetime({ mode: 'date' });
mysql.timestamp({ mode: 'date' });

sqlite.integer({ mode: 'timestamp' });
sqlite.integer({ mode: 'timestamp_ms' });

// Schema
Type.Date();
```

```ts
pg.date({ mode: 'string' });
pg.timestamp({ mode: 'string' });
pg.cidr();
pg.inet();
pg.interval();
pg.macaddr();
pg.macaddr8();
pg.numeric();
pg.text();
pg.sparsevec();
pg.time();

mysql.binary();
mysql.date({ mode: 'string' });
mysql.datetime({ mode: 'string' });
mysql.decimal();
mysql.time();
mysql.timestamp({ mode: 'string' });
mysql.varbinary();

sqlite.numeric();
sqlite.text({ mode: 'text' });

// Schema
Type.String();
```

```ts
pg.bit({ dimensions: ... });

// Schema
t.RegExp(/^[01]+$/, { maxLength: dimensions });
```

```ts
pg.uuid();

// Schema
Type.String({ format: 'uuid' });
```

```ts
pg.char({ length: ... });

mysql.char({ length: ... });

// Schema
Type.String({ minLength: length, maxLength: length });
```

```ts
pg.varchar({ length: ... });

mysql.varchar({ length: ... });

sqlite.text({ mode: 'text', length: ... });

// Schema
Type.String({ maxLength: length });
```

```ts
mysql.tinytext();

// Schema
Type.String({ maxLength: 255 }); // unsigned 8-bit integer limit
```

```ts
mysql.text();

// Schema
Type.String({ maxLength: 65_535 }); // unsigned 16-bit integer limit
```

```ts
mysql.mediumtext();

// Schema
Type.String({ maxLength: 16_777_215 }); // unsigned 24-bit integer limit
```

```ts
mysql.longtext();

// Schema
Type.String({ maxLength: 4_294_967_295 }); // unsigned 32-bit integer limit
```

```ts
pg.text({ enum: ... });
pg.char({ enum: ... });
pg.varchar({ enum: ... });

mysql.tinytext({ enum: ... });
mysql.mediumtext({ enum: ... });
mysql.text({ enum: ... });
mysql.longtext({ enum: ... });
mysql.char({ enum: ... });
mysql.varchar({ enum: ... });
mysql.mysqlEnum(..., ...);

sqlite.text({ mode: 'text', enum: ... });

// Schema
Type.Enum(enum);
```

```ts
mysql.tinyint();

// Schema
Type.Integer({ minimum: -128, maximum: 127 }); // 8-bit integer lower and upper limit
```

```ts
mysql.tinyint({ unsigned: true });

// Schema
Type.Integer({ minimum: 0, maximum: 255 }); // unsigned 8-bit integer lower and upper limit
```

```ts
pg.smallint();
pg.smallserial();

mysql.smallint();

// Schema
Type.Integer({ minimum: -32_768, maximum: 32_767 }); // 16-bit integer lower and upper limit
```

```ts
mysql.smallint({ unsigned: true });

// Schema
Type.Integer({ minimum: 0, maximum: 65_535 }); // unsigned 16-bit integer lower and upper limit
```

```ts
pg.real();

mysql.float();

// Schema
Type.Number().min(-8_388_608).max(8_388_607); // 24-bit integer lower and upper limit
```

```ts
mysql.mediumint();

// Schema
Type.Integer({ minimum: -8_388_608, maximum: 8_388_607 }); // 24-bit integer lower and upper limit
```

```ts
mysql.float({ unsigned: true });

// Schema
Type.Number({ minimum: 0, maximum: 16_777_215 }); // unsigned 24-bit integer lower and upper limit
```

```ts
mysql.mediumint({ unsigned: true });

// Schema
Type.Integer({ minimum: 0, maximum: 16_777_215 }); // unsigned 24-bit integer lower and upper limit
```

```ts
pg.integer();
pg.serial();

mysql.int();

// Schema
Type.Integer({ minimum: -2_147_483_648, maximum: 2_147_483_647 }); // 32-bit integer lower and upper limit
```

```ts
mysql.int({ unsigned: true });

// Schema
Type.Integer({ minimum: 0, maximum: 4_294_967_295 }); // unsgined 32-bit integer lower and upper limit
```

```ts
pg.doublePrecision();

mysql.double();
mysql.real();

sqlite.real();

// Schema
Type.Number({ minimum: -140_737_488_355_328, maximum: 140_737_488_355_327 }); // 48-bit integer lower and upper limit
```

```ts
mysql.double({ unsigned: true });

// Schema
Type.Numer({ minimum: 0, maximum: 281_474_976_710_655 }); // unsigned 48-bit integer lower and upper limit
```

```ts
pg.bigint({ mode: 'number' });
pg.bigserial({ mode: 'number' });

mysql.bigint({ mode: 'number' });
mysql.bigserial({ mode: 'number' });

sqlite.integer({ mode: 'number' });

// Schema
Type.Integer({ minimum: -9_007_199_254_740_991, maximum: 9_007_199_254_740_991 }); // Javascript min. and max. safe integers
```

```ts
mysql.serial();

Type.Integer({ minimum: 0, maximum: 9_007_199_254_740_991 }); // Javascript max. safe integer
```

```ts
pg.bigint({ mode: 'bigint' });
pg.bigserial({ mode: 'bigint' });

mysql.bigint({ mode: 'bigint' });

sqlite.blob({ mode: 'bigint' });

// Schema
Type.BigInt({ minimum: -9_223_372_036_854_775_808n, maximum: 9_223_372_036_854_775_807n }); // 64-bit integer lower and upper limit
```

```ts
mysql.bigint({ mode: 'bigint', unsigned: true });

// Schema
Type.BigInt({ minimum: 0, maximum: 18_446_744_073_709_551_615n }); // unsigned 64-bit integer lower and upper limit
```

```ts
mysql.year();

// Schema
Type.Integer({ minimum: 1_901, maximum: 2_155 });
```

```ts
pg.geometry({ type: 'point', mode: 'tuple' });
pg.point({ mode: 'tuple' });

// Schema
Type.Tuple([Type.Number(), Type.Number()]);
```

```ts
pg.geometry({ type: 'point', mode: 'xy' });
pg.point({ mode: 'xy' });

// Schema
Type.Object({ x: Type.Number(), y: Type.Number() });
```

```ts
pg.halfvec({ dimensions: ... });
pg.vector({ dimensions: ... });

// Schema
Type.Array(Type.Number(), { minItems: dimensions, maxItems: dimensions });
```

```ts
pg.line({ mode: 'abc' });

// Schema
Type.Object({ a: Type.Number(), b: Type.Number(), c: Type.Number() });
```

```ts
pg.line({ mode: 'tuple' });

// Schema
Type.Tuple([Type.Number(), Type.Number(), Type.Number()]);
```

```ts
pg.json();
pg.jsonb();

mysql.json();

sqlite.blob({ mode: 'json' });
sqlite.text({ mode: 'json' });

// Schema
Type.Recursive((self) => Type.Union([Type.Union([Type.String(), Type.Number(), Type.Boolean(), Type.Null()]), Type.Array(self), Type.Record(Type.String(), self)]));
```

```ts
sqlite.blob({ mode: 'buffer' });

// Schema
t.Union([t.Union([t.String(), t.Number(), t.Boolean(), t.Null()]), t.Array(t.Any()), t.Record(t.String(), t.Any())]);
```

```ts
pg.dataType().array(...);

// Schema
Type.Array(baseDataTypeSchema, { minItems: size, maxItems: size });
```


Source: https://orm.drizzle.team/docs/typebox

import Npm from '@mdx/Npm.astro';
import Callout from '@mdx/Callout.astro';

<Callout type="error">
Starting from `drizzle-orm@1.0.0-beta.15`, `drizzle-typebox` has been deprecated in favor of first-class schema generation support within Drizzle ORM itself

You can still use `drizzle-typebox` package but all new update will be added to Drizzle ORM directly

This version of `typebox` is using new `typebox` package
</Callout>

# typebox

#### Install the dependencies
<Npm>
drizzle-orm@rc typebox
</Npm>

Allows you to generate [typebox](https://sinclairzx81.github.io/typebox/#/) schemas from Drizzle ORM schemas

**Features**

- Create a select schema for tables, views and enums.
- Create insert and update schemas for tables.
- Supported dialects: CockroachDB, MSSQL, MySQL, PostgreSQL, SingleStore, SQLite.

#### Usage

```ts
import { pgEnum, pgTable, serial, text, timestamp } from 'drizzle-orm/pg-core';
import { createInsertSchema, createSelectSchema, createUpdateSchema } from 'drizzle-orm/typebox';
import { Type } from 'typebox';
import { Value } from 'typebox/value';

const users = pgTable('users', {
	id: serial('id').primaryKey(),
	name: text('name').notNull(),
	email: text('email').notNull(),
	role: text('role', { enum: ['admin', 'user'] }).notNull(),
	createdAt: timestamp('created_at').notNull().defaultNow(),
});

// Schema for inserting a user - can be used to validate API requests
const insertUserSchema = createInsertSchema(users);

// Schema for updating a user - can be used to validate API requests
const updateUserSchema = createUpdateSchema(users);

// Schema for selecting a user - can be used to validate API responses
const selectUserSchema = createSelectSchema(users);

// Overriding the fields
const insertUserSchema = createInsertSchema(users, {
	role: Type.String(),
});

// Refining the fields - useful if you want to change the fields before they become nullable/optional in the final schema
const insertUserSchema = createInsertSchema(users, {
	id: (schema) => Type.Number({ ...schema, minimum: 0 }),
	role: Type.String(),
});

// Usage

const isUserValid: boolean = Value.Check(insertUserSchema, {
	name: 'John Doe',
	email: 'johndoe@test.com',
	role: 'admin',
});
```


Source: https://orm.drizzle.team/docs/upgrade-21

import Callout from '@mdx/Callout.astro';

## How to migrate to `0.21.0`

#### 1. Remove all `:dialect` prefixes from your drizzle-kit commands.
Example: Change `drizzle-kit push:mysql` to `drizzle-kit push`.

#### 2. Update your `drizzle.config.ts` file:
 - Add `dialect` to `drizzle.config.ts`. It is now mandatory and can be `postgresql`, `mysql`, or `sqlite`.
 - Add `driver` to `drizzle.config.ts` ONLY if you are using `aws-data-api`, `turso`, `d1-http`(WIP), or `expo`. Otherwise, you can remove the `driver` from `drizzle.config.ts`.
 - If you were using `connectionString` or `uri` in `dbCredentials`, you should now use `url`.
    
```ts
import { defineConfig } from "drizzle-kit"

export default defineConfig({
    dialect: "sqlite", // "postgresql" | "mysql"
    driver: "turso", // optional and used only if `aws-data-api`, `turso`, `d1-http`(WIP) or `expo` are used
    dbCredentials: {
        url: ""
    }
})
```

#### 3. If you are using PostgreSQL or SQLite and had migrations generated in your project, please run `drizzle-kit up` so Drizzle can upgrade all the snapshots to version 6.

<Callout>
  You can check everything that was changed in `0.21.0` in details here
</Callout>

## Changelog

**❗ Snapshots Upgrade**

All PostgreSQL and SQLite-generated snapshots will be upgraded to version 6. You will be prompted to upgrade them by running `drizzle-kit up`

**❗ Removing :dialect from `drizzle-kit` cli commands**

You can now just use commands, like:

- `drizzle-kit generate`
- `drizzle-kit push`
- etc.

without specifying dialect. This param is moved to `drizzle.config.ts`

**❗ `drizzle.config` update**

- `dialect` is now mandatory; specify which database dialect you are connecting to. Options include `mysql`, `postgresql`, or `sqlite`.
- `driver` has become optional and will have a specific driver, each with a different configuration of `dbCredentials`. Available drivers are:
  - `aws-data-api`
  - `turso`
  - `d1-http` - currently WIP
  - `expo`
- `url` - a unified parameter for the previously existing `connectionString` and `uri`.
- `migrations` - a new object parameter to specify a custom table and schema for the migrate command:
  - `table` - the custom table where drizzle will store migrations.
  - `schema` - the custom schema where drizzle will store migrations (Postgres only).

Usage examples for all new and updated commands
```ts
import { defineConfig } from "drizzle-kit"

export default defineConfig({
    dialect: "sqlite", // "postgresql" | "mysql"
    driver: "turso"
    dbCredentials: {
        url: ""
    },
    migration: {
        table: "migrations",
        schema: "public"
    }
})
```

Drizzle driver selection follows the current strategy:

If a `driver` is specified, use this driver for querying.

If no driver is specified:

- For `postgresql` dialect, Drizzle will:
  - Check if the `pg` driver is installed and use it.
  - If not, try to find the `postgres` driver and use it.
  - If still not found, try to find `@vercel/postgres`.
  - Then try `@neondatabase/serverless`.
  - If nothing is found, an error will be thrown.

- For `mysql` dialect, Drizzle will:
  - Check if the `mysql2` driver is installed and use it.
  - If not, try to find `@planetscale/database` and use it.
  - If nothing is found, an error will be thrown.

- For `sqlite` dialect, Drizzle will:
  - Check if the `@libsql/client` driver is installed and use it.
  - If not, try to find `better-sqlite3` and use it.
  - If nothing is found, an error will be thrown

**❗ MySQL schemas/database are no longer supported by drizzle-kit**

Drizzle Kit won't handle any schema changes for additional schemas/databases in your drizzle schema file

# New Features

**🎉 Pull relations**

Drizzle will now pull `relations` from the database by extracting foreign key information and translating it into a `relations` object. You can view the `relations.ts` file in the `out` folder after introspection is complete

For more info about relations, please check [the docs](/docs/rqb#declaring-relations)


**🎉 Custom name for generated migrations**

To specify a name for your migration you should use `--name <name>`

Usage
```
drizzle-kit generate --name init_db
```

**🎉 New command `migrate`**

You can now apply generated migrations to your database directly from `drizzle-kit`

Usage
```
drizzle-kit migrate
```

By default, drizzle-kit will store migration data entries in the `__drizzle_migrations` table and, in the case of PostgreSQL, in a `drizzle` schema. If you want to change this, you will need to specify the modifications in `drizzle.config.ts`.

```ts
import { defineConfig } from "drizzle-kit"

export default defineConfig({
    migrations: {
        table: "migrations",
        schema: "public"
    }
})
```

Source: https://orm.drizzle.team/docs/upgrade-v1

import Npm from "@mdx/Npm.astro";
import Npx from "@mdx/Npx.astro";
import Prerequisites from "@mdx/Prerequisites.astro";

# Upgrading to Drizzle v1

<Npm>
 drizzle-orm@rc
 -D drizzle-kit@rc
</Npm>

#### Step 1 - Run `drizzle-kit up`

> v3 migration folder discussion: https://github.com/drizzle-team/drizzle-orm/discussions/2832  

We've updated the migrations folder structure by:
- removing `journal.json`
- grouping SQL files and snapshots into separate migration folders
- removing the `drizzle-kit drop` command

These changes eliminate potential Git conflicts with the journal file and simplify the process of dropping or fixing conflicted migrations

The drizzle-kit has been architecturally redesigned:
- Migrated from database snapshots to DDL snapshots

Commutativity checks were added:
- Detecting non-commutative migrations across branches
> Commutativity discussion: https://github.com/drizzle-team/drizzle-orm/discussions/5005

To migrate from old structure to a new one you would need to run

<Npx>
drizzle-kit up
</Npx>

#### Step 2 - Review breaking changes

You can find out the full list of breaking changes [here](/docs/v0-v1-changes#breaking-changes) and make sure to update your code accordingly

If you were using Relational Queries, you need to upgrade to v2:
- [How to migrate relations definition from v1 to v2](/docs/relations-v1-v2#how-to-migrate-relations-schema-definition-from-v1-to-v2)
- [How to migrate queries from v1 to v2](/docs/relations-v1-v2#how-to-migrate-queries-from-v1-to-v2)

#### Step 3 - Done ✅


Source: https://orm.drizzle.team/docs/valibot

import Npm from '@mdx/Npm.astro';
import Callout from '@mdx/Callout.astro';

<Callout type="error">
Starting from `drizzle-orm@1.0.0-beta.15`, `drizzle-valibot` has been deprecated in favor of first-class schema generation support within Drizzle ORM itself

You can still use `drizzle-valibot` package but all new update will be added to Drizzle ORM directly
</Callout>

# valibot

### Install the dependencies

<Npm>
valibot
</Npm>

### Select schema

Defines the shape of data queried from the database - can be used to validate API responses.

```ts copy
import { pgTable, text, integer } from 'drizzle-orm/pg-core';
import { createSelectSchema } from 'drizzle-orm/valibot';
import { parse } from 'valibot';

const users = pgTable('users', {
  id: integer().generatedAlwaysAsIdentity().primaryKey(),
  name: text().notNull(),
  age: integer().notNull()
});

const userSelectSchema = createSelectSchema(users);

const rows = await db.select({ id: users.id, name: users.name }).from(users).limit(1);
const parsed: { id: number; name: string; age: number } = parse(userSelectSchema, rows[0]); // Error: `age` is not returned in the above query

const rows = await db.select().from(users).limit(1);
const parsed: { id: number; name: string; age: number } = parse(userSelectSchema, rows[0]); // Will parse successfully
```

Views and enums are also supported.

```ts copy
import { pgEnum } from 'drizzle-orm/pg-core';
import { createSelectSchema } from 'drizzle-orm/valibot';
import { parse } from 'valibot';

const roles = pgEnum('roles', ['admin', 'basic']);
const rolesSchema = createSelectSchema(roles);
const parsed: 'admin' | 'basic' = parse(rolesSchema, ...);

const usersView = pgView('users_view').as((qb) => qb.select().from(users).where(gt(users.age, 18)));
const usersViewSchema = createSelectSchema(usersView);
const parsed: { id: number; name: string; age: number } = parse(usersViewSchema, ...);
```

### Insert schema

Defines the shape of data to be inserted into the database - can be used to validate API requests.

```ts copy
import { pgTable, text, integer } from 'drizzle-orm/pg-core';
import { createInsertSchema } from 'drizzle-orm/valibot';
import { parse } from 'valibot';

const users = pgTable('users', {
  id: integer().generatedAlwaysAsIdentity().primaryKey(),
  name: text().notNull(),
  age: integer().notNull()
});

const userInsertSchema = createInsertSchema(users);

const user = { name: 'John' };
const parsed: { name: string, age: number } = parse(userInsertSchema, user); // Error: `age` is not defined

const user = { name: 'Jane', age: 30 };
const parsed: { name: string, age: number } = parse(userInsertSchema, user); // Will parse successfully
await db.insert(users).values(parsed);
```

### Update schema

Defines the shape of data to be updated in the database - can be used to validate API requests.

```ts copy
import { pgTable, text, integer } from 'drizzle-orm/pg-core';
import { createUpdateSchema } from 'drizzle-orm/valibot';
import { parse } from 'valibot';

const users = pgTable('users', {
  id: integer().generatedAlwaysAsIdentity().primaryKey(),
  name: text().notNull(),
  age: integer().notNull()
});

const userUpdateSchema = createUpdateSchema(users);

const user = { id: 5, name: 'John' };
const parsed: { name?: string | undefined, age?: number | undefined } = parse(userUpdateSchema, user); // Error: `id` is a generated column, it can't be updated

const user = { age: 35 };
const parsed: { name?: string | undefined, age?: number | undefined } = parse(userUpdateSchema, user); // Will parse successfully
await db.update(users).set(parsed).where(eq(users.name, 'Jane'));
```

### Refinements

Each create schema function accepts an additional optional parameter that you can used to extend, modify or completely overwite a field's schema. Defining a callback function will extend or modify while providing a Valibot schema will overwrite it.

```ts copy
import { pgTable, text, integer, json } from 'drizzle-orm/pg-core';
import { createSelectSchema } from 'drizzle-orm/valibot';
import { parse, pipe, maxLength, object, string } from 'valibot';

const users = pgTable('users', {
  id: integer().generatedAlwaysAsIdentity().primaryKey(),
  name: text().notNull(),
  bio: text(),
  preferences: json()
});

const userSelectSchema = createSelectSchema(users, {
  name: (schema) => pipe(schema, maxLength(20)), // Extends schema
  bio: (schema) => pipe(schema, maxLength(1000)), // Extends schema before becoming nullable/optional
  preferences: object({ theme: string() }) // Overwrites the field, including its nullability
});

const parsed: {
  id: number;
  name: string,
  bio?: string | undefined;
  preferences: {
    theme: string;
  };
} = parse(userSelectSchema, ...);
```

### Data type reference

```ts
pg.boolean();

mysql.boolean();

sqlite.integer({ mode: 'boolean' });

// Schema
boolean();
```

```ts
pg.date({ mode: 'date' });
pg.timestamp({ mode: 'date' });

mysql.date({ mode: 'date' });
mysql.datetime({ mode: 'date' });
mysql.timestamp({ mode: 'date' });

sqlite.integer({ mode: 'timestamp' });
sqlite.integer({ mode: 'timestamp_ms' });

// Schema
date();
```

```ts
pg.date({ mode: 'string' });
pg.timestamp({ mode: 'string' });
pg.cidr();
pg.inet();
pg.interval();
pg.macaddr();
pg.macaddr8();
pg.numeric();
pg.text();
pg.sparsevec();
pg.time();

mysql.binary();
mysql.date({ mode: 'string' });
mysql.datetime({ mode: 'string' });
mysql.decimal();
mysql.time();
mysql.timestamp({ mode: 'string' });
mysql.varbinary();

sqlite.numeric();
sqlite.text({ mode: 'text' });

// Schema
string();
```

```ts
pg.bit({ dimensions: ... });

// Schema
pipe(string(), regex(/^[01]+$/), maxLength(dimensions));
```

```ts
pg.uuid();

// Schema
pipe(string(), uuid());
```

```ts
pg.char({ length: ... });

mysql.char({ length: ... });

// Schema
pipe(string(), length(length));
```

```ts
pg.varchar({ length: ... });

mysql.varchar({ length: ... });

sqlite.text({ mode: 'text', length: ... });

// Schema
pipe(string(), maxLength(length));
```

```ts
mysql.tinytext();

// Schema
pipe(string(), maxLength(255)); // unsigned 8-bit integer limit
```

```ts
mysql.text();

// Schema
pipe(string(), maxLength(65_535)); // unsigned 16-bit integer limit
```

```ts
mysql.mediumtext();

// Schema
pipe(string(), maxLength(16_777_215)); // unsigned 24-bit integer limit
```

```ts
mysql.longtext();

// Schema
pipe(string(), maxLength(4_294_967_295)); // unsigned 32-bit integer limit
```

```ts
pg.text({ enum: ... });
pg.char({ enum: ... });
pg.varchar({ enum: ... });

mysql.tinytext({ enum: ... });
mysql.mediumtext({ enum: ... });
mysql.text({ enum: ... });
mysql.longtext({ enum: ... });
mysql.char({ enum: ... });
mysql.varchar({ enum: ... });
mysql.mysqlEnum(..., ...);

sqlite.text({ mode: 'text', enum: ... });

// Schema
enum(enum);
```

```ts
mysql.tinyint();

// Schema
pipe(number(), minValue(-128), maxValue(127), integer()); // 8-bit integer lower and upper limit
```

```ts
mysql.tinyint({ unsigned: true });

// Schema
pipe(number(), minValue(0), maxValue(255), integer()); // unsigned 8-bit integer lower and upper limit
```

```ts
pg.smallint();
pg.smallserial();

mysql.smallint();

// Schema
pipe(number(), minValue(-32_768), maxValue(32_767), integer()); // 16-bit integer lower and upper limit
```

```ts
mysql.smallint({ unsigned: true });

// Schema
pipe(number(), minValue(0), maxValue(65_535), integer()); // unsigned 16-bit integer lower and upper limit
```

```ts
pg.real();

mysql.float();

// Schema
pipe(number(), minValue(-8_388_608), maxValue(8_388_607)); // 24-bit integer lower and upper limit
```

```ts
mysql.mediumint();

// Schema
pipe(number(), minValue(-8_388_608), maxValue(8_388_607), integer()); // 24-bit integer lower and upper limit
```

```ts
mysql.float({ unsigned: true });

// Schema
pipe(number(), minValue(0), maxValue(16_777_215)); // unsigned 24-bit integer lower and upper limit
```

```ts
mysql.mediumint({ unsigned: true });

// Schema
pipe(number(), minValue(0), maxValue(16_777_215), integer()); // unsigned 24-bit integer lower and upper limit
```

```ts
pg.integer();
pg.serial();

mysql.int();

// Schema
pipe(number(), minValue(-2_147_483_648), maxValue(2_147_483_647), integer()); // 32-bit integer lower and upper limit
```

```ts
mysql.int({ unsigned: true });

// Schema
pipe(number(), minValue(0), maxValue(4_294_967_295), integer()); // unsgined 32-bit integer lower and upper limit
```

```ts
pg.doublePrecision();

mysql.double();
mysql.real();

sqlite.real();

// Schema
pipe(number(), minValue(-140_737_488_355_328), maxValue(140_737_488_355_327)); // 48-bit integer lower and upper limit
```

```ts
mysql.double({ unsigned: true });

// Schema
pipe(number(), minValue(0), maxValue(281_474_976_710_655)); // unsigned 48-bit integer lower and upper limit
```

```ts
pg.bigint({ mode: 'number' });
pg.bigserial({ mode: 'number' });

mysql.bigint({ mode: 'number' });
mysql.bigserial({ mode: 'number' });

sqlite.integer({ mode: 'number' });

// Schema
pipe(number(), minValue(-9_007_199_254_740_991), maxValue(9_007_199_254_740_991), integer()); // Javascript min. and max. safe integers
```

```ts
mysql.serial();

// Schema
pipe(number(), minValue(0), maxValue(9_007_199_254_740_991), integer()); // Javascript max. safe integer
```

```ts
pg.bigint({ mode: 'bigint' });
pg.bigserial({ mode: 'bigint' });

mysql.bigint({ mode: 'bigint' });

sqlite.blob({ mode: 'bigint' });

// Schema
pipe(bigint(), minValue(-9_223_372_036_854_775_808n), maxValue(9_223_372_036_854_775_807n)); // 64-bit integer lower and upper limit
```

```ts
mysql.bigint({ mode: 'bigint', unsigned: true });

// Schema
pipe(bigint(), minValue(0n), maxValue(18_446_744_073_709_551_615n)); // unsigned 64-bit integer lower and upper limit
```

```ts
mysql.year();

// Schema
pipe(number(), minValue(1_901), maxValue(2_155), integer());
```

```ts
pg.geometry({ type: 'point', mode: 'tuple' });
pg.point({ mode: 'tuple' });

// Schema
tuple([number(), number()]);
```

```ts
pg.geometry({ type: 'point', mode: 'xy' });
pg.point({ mode: 'xy' });

// Schema
object({ x: number(), y: number() });
```

```ts
pg.halfvec({ dimensions: ... });
pg.vector({ dimensions: ... });

// Schema
pipe(array(number()), length(dimensions));
```

```ts
pg.line({ mode: 'abc' });

// Schema
object({ a: number(), b: number(), c: number() });
```

```ts
pg.line({ mode: 'tuple' });

// Schema
tuple([number(), number(), number()]);
```

```ts
pg.json();
pg.jsonb();

mysql.json();

sqlite.blob({ mode: 'json' });
sqlite.text({ mode: 'json' });

// Schema
union([union([string(), number(), boolean(), null_()]), array(any()), record(string(), any())]);
```

```ts
sqlite.blob({ mode: 'buffer' });

// Schema
custom<Buffer>((v) => v instanceof Buffer);
```

```ts
pg.dataType().array(...);

// Schema
pipe(array(baseDataTypeSchema), length(size));
```


Source: https://orm.drizzle.team/docs/why-drizzle

import Callout from '@mdx/Callout.astro';
import CodeTabs from '@mdx/CodeTabs.astro';
import YoutubeCards from '@mdx/YoutubeCards.astro';

# Drizzle ORM  
> Drizzle is a good friend who's there for you when necessary and doesn't bother when you need some space.

Drizzle ORM is a headless TypeScript ORM with a head. 🐲

It looks and feels simple, performs on day _1000_ of your project, 
lets you do things your way, and is there when you need it.  

**It's the only ORM with both [relational](/docs/rqb) and [SQL-like](/docs/select) query APIs**, 
providing you the best of both worlds when it comes to accessing your relational data. 
Drizzle is lightweight, performant, typesafe, non-lactose, gluten-free, sober, flexible and **serverless-ready by design**.
Drizzle is not just a library, it's an experience. 🤩

[![Drizzle bestofjs](@/assets/images/bestofjs.jpg)](https://bestofjs.org/projects/drizzle-orm)

## Headless ORM? 
First and foremost, Drizzle is a library and a collection of complementary opt-in tools. 

**ORM** stands for _object relational mapping_, and developers tend to call Django-like or Spring-like tools an ORM. 
We truly believe it's a misconception based on legacy nomenclature, and we call them **data frameworks**.

<Callout type="error" emoji="️💔">
  With data frameworks you have to build projects **around them** and not **with them**.
</Callout>

**Drizzle** lets you build your project the way you want, without interfering with your project or structure. 

Using Drizzle you can define and manage database schemas in TypeScript, access your data in a SQL-like 
or relational way, and take advantage of opt-in tools 
to push your developer experience _through the roof_. 🤯 

## Why SQL-like?
**If you know SQL, you know Drizzle.**

Other ORMs and data frameworks tend to deviate/abstract you away from SQL, which 
leads to a double learning curve: needing to know both SQL and the framework's API.  

Drizzle is the opposite. 
We embrace SQL and built Drizzle to be SQL-like at its core, so you can have zero to no 
learning curve and access to the full power of SQL.  

We bring all the familiar **[SQL schema](/docs/sql-schema-declaration)**, **[queries](/docs/select)**, 
**[automatic migrations](/docs/migrations)** and **[one more thing](/docs/rqb)**. ✨

<CodeTabs items={["index.ts", "schema.ts", "migration.sql"]}>
```typescript copy
// Access your data
await db
	.select()
	.from(countries)
	.leftJoin(cities, eq(cities.countryId, countries.id))
	.where(eq(countries.id, 10))
```
```typescript copy
// manage your schema
export const countries = pgTable('countries', {
  id: serial('id').primaryKey(),
  name: varchar('name', { length: 256 }),
});

export const cities = pgTable('cities', {
  id: serial('id').primaryKey(),
  name: varchar('name', { length: 256 }),
  countryId: integer('country_id').references(() => countries.id),
});
```
```sql
-- generate migrations
CREATE TABLE IF NOT EXISTS "countries" (
	"id" serial PRIMARY KEY NOT NULL,
	"name" varchar(256)
);

CREATE TABLE IF NOT EXISTS "cities" (
	"id" serial PRIMARY KEY NOT NULL,
	"name" varchar(256),
	"country_id" integer
);

ALTER TABLE "cities" ADD CONSTRAINT "cities_country_id_countries_id_fk" FOREIGN KEY ("country_id") REFERENCES "countries"("id") ON DELETE no action ON UPDATE no action;
```
</CodeTabs>

## Why not SQL-like?
We're always striving for a perfectly balanced solution, and while SQL-like does cover 100% of the needs, 
there are certain common scenarios where you can query data in a better way.  

We've built the **[Queries API](/docs/rqb)** for you, so you can fetch relational nested data from the database 
in the most convenient and performant way, and never think about joins and data mapping.  

**Drizzle always outputs exactly 1 SQL query.** Feel free to use it with serverless databases and never worry about performance or roundtrip costs!

```ts
const result = await db.query.users.findMany({
	with: {
		posts: true
	},
});
```

## Serverless?
<Callout type="info" emoji="🥳">
  The best part is no part. **Drizzle has exactly 0 dependencies!**
</Callout>


![Drizzle is slim an Serverless ready](@/assets/images/drizzle31kb.jpg)
  
Drizzle ORM is dialect-specific, slim, performant and serverless-ready **by design**.  

We've spent a lot of time to make sure you have best-in-class SQL dialect support, including Postgres, MySQL, and others.

Drizzle operates natively through industry-standard database drivers. We support all major **[PostgreSQL](/docs/get-started-postgresql)**, **[MySQL](/docs/mysql/get-started-mysql)** or **[SQLite](/docs/sqlite/get-started-sqlite)** drivers out there, and we're adding new ones **[really fast](https://twitter.com/DrizzleORM/status/1653082492742647811?s=20)**.  


## Welcome on board!
More and more companies are adopting Drizzle in production, experiencing immense benefits in both DX and performance.

**We're always there to help, so don't hesitate to reach out. We'll gladly assist you in your Drizzle journey!**

We have an outstanding **[Discord community](https://driz.link/discord)** and welcome all builders to our **[Twitter](https://twitter.com/drizzleorm)**.
  
Now go build something awesome with Drizzle and your **[PostgreSQL](/docs/get-started-postgresql)**, **[MySQL](/docs/mysql/get-started-mysql)** or **[SQLite](/docs/sqlite/get-started-sqlite)** database. 🚀

### Video Showcase

{/* tRPC + NextJS App Router = Simple Typesafe APIs
Jack Herrington 19:17
https://www.youtube.com/watch?v=qCLV0Iaq9zU */}
{/* https://www.youtube.com/watch?v=qDunJ0wVIec */}
{/* https://www.youtube.com/watch?v=NZpPMlSAez0 */}

 {/* https://www.youtube.com/watch?v=-A0kMiJqQRY */}

<YoutubeCards cards={[
	{
		id: "vyU5mJGCJMw",
		title: "Full Drizzle Course for Beginners",
		description: "Code Genix",
		time: "1:37:39",
	},
	{
		id: "7-NZ0MlPpJA",
		title: "Learn Drizzle In 60 Minutes",
		description: "Web Dev Simplified",
		time: "56:09"
	},
	{
		id: "i_mAHOhpBSA",
		title: "Drizzle ORM in 100 Seconds",
		description: "Fireship",
		time: "2:55"
	},
	{
		id: "hIYNOiZXQ7Y",
		title: "Learn Drizzle ORM in 13 mins (crash course)",
		description: "Neon",
		time: "14:00"
	},
	{
		id: "4ZhtoOFKFP8",
		title: "Easiest Database Setup in Next.js&nbsp;14 with Turso&nbsp;&&nbsp;Drizzle",
		description: "Sam Meech-Ward",
		time: '38:08'
	}, 
	{
		id: "NfVELsEZFsA",
		title: "Next.js Project with Vercel, Neon, Drizzle, TailwindCSS, FlowBite and more!",
		description: "CodingEntrepreneurs",
		time: '5:46:28'
	}, 
	{
		id: "_SLxGYzv6jo",
		title: "I Have A New Favorite Database&nbsp;Tool",
		description: "Theo - t3.gg",
		time: '5:46'
	}, 
	{
		id: "Qo-RXkSwOtc",
		title: "Drizzle ORM First impressions - migrations, relations, queries!",
		description: "Marius Espejo",
		time: '33:52'
	},
	{
		id: "yXNEqyvA0OY",
		title: "I want to learn Drizzle ORM, so I'm starting another next14 project",
		description: "Web Dev Cody",
		time: "9:00"
	},
	{
		id: "h7vVhR-dFYo",
		title: "Picking an ORM is Getting Harder...",
		description: "Ben Davis",
		time: "5:18"
	},
	{
		id: "8met6WTk0mQ",
		title: "This New Database Tool is a Game-Changer",
		description: "Josh tried coding",
		time: "8:49"
	},
	{
		id: "woWW1T9DXEY",
		title: "My Favorite Database Tool Just Got EVEN Better",
		description: "Josh tried coding",
		time: "4:23"
	},
	{
		id: "A3l6YYkXzzg",
		title: "SaaS Notion Clone with Realtime cursors, Nextjs 13, Stripe, Drizzle ORM, Tailwind, Supabase, Sockets",
		description: "Web Prodigies",
		time: "11:41:46"
	},
	{
		id: "EQfaw5bDE1s",
		title: "SvelteKit + Drizzle Code Breakdown",
		description: "Ben Davis",
		time: "12:18"
	},
	{
		id: "b6VhN_HHDiQ",
		title: "Build a Multi-Tenanted, Role-Based Access Control System",
		description: "TomDoesTech",
		time: "2:01:29"
	},
	/*
	This video became private
	Uncomment (in other files too) it when it becomes public again
	{
		id: "3tl9XCiQErA",
		title: "The Prisma killer is finally here",
		description: "SST",
		time: "5:42"
	},
	*/
	{
		id: "VQFjyEa8vGE",
		title: "Learning Drizzle ORM and working on a next14 project",
		description: "Web Dev Cody",
		time: "1:07:41"
	},
	{
		id: "5G0upg4sxgE",
		title: "This Trick Makes My Favorite Database Tool Even Better",
		description: "Josh tried coding",
		time: "6:01"
	},
	{
		id: "-JnEuvPmt-Q",
		title: "Effortless Auth in Next.js 14: Use Auth.js & Drizzle ORM for Secure Login",
		description: "Sam Meech-Ward",
		time: "26:29"
	},
]} />


Source: https://orm.drizzle.team/docs/zod

import Npm from '@mdx/Npm.astro';
import Callout from '@mdx/Callout.astro';

<Callout type="error">
Starting from `drizzle-orm@1.0.0-beta.15`, `drizzle-zod` has been deprecated in favor of first-class schema generation support within Drizzle ORM itself

You can still use `drizzle-zod` package but all new update will be added to Drizzle ORM directly
</Callout>

# zod

### Install the dependencies

<Npm>
zod
</Npm>

### Select schema

Defines the shape of data queried from the database - can be used to validate API responses.

```ts copy
import { pgTable, text, integer } from 'drizzle-orm/pg-core';
import { createSelectSchema } from 'drizzle-orm/zod';

const users = pgTable('users', {
  id: integer().generatedAlwaysAsIdentity().primaryKey(),
  name: text().notNull(),
  age: integer().notNull()
});

const userSelectSchema = createSelectSchema(users);

const rows = await db.select({ id: users.id, name: users.name }).from(users).limit(1);
const parsed: { id: number; name: string; age: number } = userSelectSchema.parse(rows[0]); // Error: `age` is not returned in the above query

const rows = await db.select().from(users).limit(1);
const parsed: { id: number; name: string; age: number } = userSelectSchema.parse(rows[0]); // Will parse successfully
```

Views and enums are also supported.

```ts copy
import { pgEnum } from 'drizzle-orm/pg-core';
import { createSelectSchema } from 'drizzle-orm/zod';

const roles = pgEnum('roles', ['admin', 'basic']);
const rolesSchema = createSelectSchema(roles);
const parsed: 'admin' | 'basic' = rolesSchema.parse(...);

const usersView = pgView('users_view').as((qb) => qb.select().from(users).where(gt(users.age, 18)));
const usersViewSchema = createSelectSchema(usersView);
const parsed: { id: number; name: string; age: number } = usersViewSchema.parse(...);
```

### Insert schema

Defines the shape of data to be inserted into the database - can be used to validate API requests.

```ts copy
import { pgTable, text, integer } from 'drizzle-orm/pg-core';
import { createInsertSchema } from 'drizzle-orm/zod';

const users = pgTable('users', {
  id: integer().generatedAlwaysAsIdentity().primaryKey(),
  name: text().notNull(),
  age: integer().notNull()
});

const userInsertSchema = createInsertSchema(users);

const user = { name: 'John' };
const parsed: { name: string, age: number } = userInsertSchema.parse(user); // Error: `age` is not defined

const user = { name: 'Jane', age: 30 };
const parsed: { name: string, age: number } = userInsertSchema.parse(user); // Will parse successfully
await db.insert(users).values(parsed);
```

### Update schema

Defines the shape of data to be updated in the database - can be used to validate API requests.

```ts copy
import { pgTable, text, integer } from 'drizzle-orm/pg-core';
import { createUpdateSchema } from 'drizzle-orm/zod';

const users = pgTable('users', {
  id: integer().generatedAlwaysAsIdentity().primaryKey(),
  name: text().notNull(),
  age: integer().notNull()
});

const userUpdateSchema = createUpdateSchema(users);

const user = { id: 5, name: 'John' };
const parsed: { name?: string | undefined, age?: number | undefined } = userUpdateSchema.parse(user); // Error: `id` is a generated column, it can't be updated

const user = { age: 35 };
const parsed: { name?: string | undefined, age?: number | undefined } = userUpdateSchema.parse(user); // Will parse successfully
await db.update(users).set(parsed).where(eq(users.name, 'Jane'));
```

### Refinements

Each create schema function accepts an additional optional parameter that you can used to extend, modify or completely overwite a field's schema. Defining a callback function will extend or modify while providing a Zod schema will overwrite it.

```ts copy
import { pgTable, text, integer, json } from 'drizzle-orm/pg-core';
import { createSelectSchema } from 'drizzle-orm/zod';
import { z } from 'zod/v4';

const users = pgTable('users', {
  id: integer().primaryKey(),
  name: text().notNull(),
  bio: text(),
  preferences: json()
});

const userSelectSchema = createSelectSchema(users, {
  name: (schema) => schema.max(20), // Extends schema
  bio: (schema) => schema.max(1000), // Extends schema before becoming nullable/optional
  preferences: z.object({ theme: z.string() }) // Overwrites the field, including its nullability
});

const parsed: {
  id: number;
  name: string,
  bio?: string | undefined;
  preferences: {
    theme: string;
  };
} = userSelectSchema.parse(...);
```

### Factory functions

For more advanced use cases, you can use the `createSchemaFactory` function.

**Use case: Using an extended Zod instance**

```ts copy
import { pgTable, text, integer } from 'drizzle-orm/pg-core';
import { createSchemaFactory } from 'drizzle-orm/zod';
import { z } from '@hono/zod-openapi'; // Extended Zod instance

const users = pgTable('users', {
  id: integer().generatedAlwaysAsIdentity().primaryKey(),
  name: text().notNull(),
  age: integer().notNull()
});

const { createInsertSchema } = createSchemaFactory({ zodInstance: z });

const userInsertSchema = createInsertSchema(users, {
  // We can now use the extended instance
  name: (schema) => schema.openapi({ example: 'John' })
});
```

**Use case: Type coercion**

```ts copy
import { pgTable, timestamp } from 'drizzle-orm/pg-core';
import { createSchemaFactory } from 'drizzle-orm/zod';
import { z } from 'zod/v4';

const users = pgTable('users', {
  ...,
  createdAt: timestamp().notNull()
});

const { createInsertSchema } = createSchemaFactory({
  // This configuration will only coerce dates. Set `coerce` to `true` to coerce all data types or specify others
  coerce: {
    date: true
  }
});

const userInsertSchema = createInsertSchema(users);
// The above is the same as this:
const userInsertSchema = z.object({
  ...,
  createdAt: z.coerce.date()
});
```

### Data type reference

```ts
pg.boolean();

mysql.boolean();

sqlite.integer({ mode: 'boolean' });

// Schema
z.boolean();
```

```ts
pg.date({ mode: 'date' });
pg.timestamp({ mode: 'date' });

mysql.date({ mode: 'date' });
mysql.datetime({ mode: 'date' });
mysql.timestamp({ mode: 'date' });

sqlite.integer({ mode: 'timestamp' });
sqlite.integer({ mode: 'timestamp_ms' });

// Schema
z.date();
```

```ts
pg.date({ mode: 'string' });
pg.timestamp({ mode: 'string' });
pg.cidr();
pg.inet();
pg.interval();
pg.macaddr();
pg.macaddr8();
pg.numeric();
pg.text();
pg.sparsevec();
pg.time();

mysql.binary();
mysql.date({ mode: 'string' });
mysql.datetime({ mode: 'string' });
mysql.decimal();
mysql.time();
mysql.timestamp({ mode: 'string' });
mysql.varbinary();

sqlite.numeric();
sqlite.text({ mode: 'text' });

// Schema
z.string();
```

```ts
pg.bit({ dimensions: ... });

// Schema
z.string().regex(/^[01]+$/).max(dimensions);
```

```ts
pg.uuid();

// Schema
z.string().uuid();
```

```ts
pg.char({ length: ... });

mysql.char({ length: ... });

// Schema
z.string().length(length);
```

```ts
pg.varchar({ length: ... });

mysql.varchar({ length: ... });

sqlite.text({ mode: 'text', length: ... });

// Schema
z.string().max(length);
```

```ts
mysql.tinytext();

// Schema
z.string().max(255); // unsigned 8-bit integer limit
```

```ts
mysql.text();

// Schema
z.string().max(65_535); // unsigned 16-bit integer limit
```

```ts
mysql.mediumtext();

// Schema
z.string().max(16_777_215); // unsigned 24-bit integer limit
```

```ts
mysql.longtext();

// Schema
z.string().max(4_294_967_295); // unsigned 32-bit integer limit
```

```ts
pg.text({ enum: ... });
pg.char({ enum: ... });
pg.varchar({ enum: ... });

mysql.tinytext({ enum: ... });
mysql.mediumtext({ enum: ... });
mysql.text({ enum: ... });
mysql.longtext({ enum: ... });
mysql.char({ enum: ... });
mysql.varchar({ enum: ... });
mysql.mysqlEnum(..., ...);

sqlite.text({ mode: 'text', enum: ... });

// Schema
z.enum(enum);
```

```ts
mysql.tinyint();

// Schema
z.number().min(-128).max(127).int(); // 8-bit integer lower and upper limit
```

```ts
mysql.tinyint({ unsigned: true });

// Schema
z.number().min(0).max(255).int(); // unsigned 8-bit integer lower and upper limit
```

```ts
pg.smallint();
pg.smallserial();

mysql.smallint();

// Schema
z.number().min(-32_768).max(32_767).int(); // 16-bit integer lower and upper limit
```

```ts
mysql.smallint({ unsigned: true });

// Schema
z.number().min(0).max(65_535).int(); // unsigned 16-bit integer lower and upper limit
```

```ts
pg.real();

mysql.float();

// Schema
z.number().min(-8_388_608).max(8_388_607); // 24-bit integer lower and upper limit
```

```ts
mysql.mediumint();

// Schema
z.number().min(-8_388_608).max(8_388_607).int(); // 24-bit integer lower and upper limit
```

```ts
mysql.float({ unsigned: true });

// Schema
z.number().min(0).max(16_777_215); // unsigned 24-bit integer lower and upper limit
```

```ts
mysql.mediumint({ unsigned: true });

// Schema
z.number().min(0).max(16_777_215).int(); // unsigned 24-bit integer lower and upper limit
```

```ts
pg.integer();
pg.serial();

mysql.int();

// Schema
z.number().min(-2_147_483_648).max(2_147_483_647).int(); // 32-bit integer lower and upper limit
```

```ts
mysql.int({ unsigned: true });

// Schema
z.number().min(0).max(4_294_967_295).int(); // unsgined 32-bit integer lower and upper limit
```

```ts
pg.doublePrecision();

mysql.double();
mysql.real();

sqlite.real();

// Schema
z.number().min(-140_737_488_355_328).max(140_737_488_355_327); // 48-bit integer lower and upper limit
```

```ts
mysql.double({ unsigned: true });

// Schema
z.number().min(0).max(281_474_976_710_655); // unsigned 48-bit integer lower and upper limit
```

```ts
pg.bigint({ mode: 'number' });
pg.bigserial({ mode: 'number' });

mysql.bigint({ mode: 'number' });
mysql.bigserial({ mode: 'number' });

sqlite.integer({ mode: 'number' });

// Schema
z.number().min(-9_007_199_254_740_991).max(9_007_199_254_740_991).int(); // Javascript min. and max. safe integers
```

```ts
mysql.serial();

// Schema
z.number().min(0).max(9_007_199_254_740_991).int(); // Javascript max. safe integer
```

```ts
pg.bigint({ mode: 'bigint' });
pg.bigserial({ mode: 'bigint' });

mysql.bigint({ mode: 'bigint' });

sqlite.blob({ mode: 'bigint' });

// Schema
z.bigint().min(-9_223_372_036_854_775_808n).max(9_223_372_036_854_775_807n); // 64-bit integer lower and upper limit
```

```ts
mysql.bigint({ mode: 'bigint', unsigned: true });

// Schema
z.bigint().min(0).max(18_446_744_073_709_551_615n); // unsigned 64-bit integer lower and upper limit
```

```ts
mysql.year();

// Schema
z.number().min(1_901).max(2_155).int();
```

```ts
pg.geometry({ type: 'point', mode: 'tuple' });
pg.point({ mode: 'tuple' });

// Schema
z.tuple([z.number(), z.number()]);
```

```ts
pg.geometry({ type: 'point', mode: 'xy' });
pg.point({ mode: 'xy' });

// Schema
z.object({ x: z.number(), y: z.number() });
```

```ts
pg.halfvec({ dimensions: ... });
pg.vector({ dimensions: ... });

// Schema
z.array(z.number()).length(dimensions);
```

```ts
pg.line({ mode: 'abc' });

// Schema
z.object({ a: z.number(), b: z.number(), c: z.number() });
```

```ts
pg.line({ mode: 'tuple' });

// Schema
z.tuple([z.number(), z.number(), z.number()]);
```

```ts
pg.json();
pg.jsonb();

mysql.json();

sqlite.blob({ mode: 'json' });
sqlite.text({ mode: 'json' });

// Schema
z.union([z.union([z.string(), z.number(), z.boolean(), z.null()]), z.record(z.any()), z.array(z.any())]);
```

```ts
sqlite.blob({ mode: 'buffer' });

// Schema
z.custom<Buffer>((v) => v instanceof Buffer);
```

```ts
pg.dataType().array(...);

// Schema
z.array(baseDataTypeSchema).length(size);
```


Source: https://orm.drizzle.team/drizzle-studio/overview

Live demo
    
  
  

Three years ago, when we shipped the first major version of Drizzle ORM and started gaining traction,
our main audience — coming from Prisma — had two requirements: **Relational Queries syntax** and a
**local database browser**.

We had commercial development experience and got things done with Beekeeper, Postico or TablePlus, so we
declined multiple times, suggesting they just use the industry default tools. They were very insistent,
and we gave up. How much time could it even take, we thought.

And we've built one. Drizzle Studio is a modern database browser — browse and edit your data, explore your
schema and run SQL, with zero setup on top of your existing database. It now comes in five flavours:

| | | |
| :------ | :--------- | :------ |
|  **[Local Studio](#drizzle-studio-for-local-development)** | free         | `drizzle-kit studio` in your Drizzle project                                           |
|  **[Drizzle Gateway](#drizzle-gateway)** | free         | self-hosted Studio for your infrastructure, deployed as a Docker container or a binary |
|  **[Chrome extension](#drizzle-studio-chrome-extension)** | free         | browse serverless databases right in their vendor consoles                             |
|  **[Studio Component](#drizzle-studio-component)** | B2B offering | embeddable Studio for your own product                                                 |
|  **[Desktop app](#drizzle-studio-desktop-app)** | coming soon | a native database browser, no terminal required                                        |

## What you can do
- **Browse data** with pagination, filtering, multi-column sorting and column reordering
- **Edit data** inline — add, update and delete rows, in-place editable `json`, `boolean` and `enum` editors
- **Copy & paste** cell ranges, copy rows to clipboard or export them as `json`/`csv`/`sql`
- **Import** `json`, `csv` and `sql` files
- **Run SQL** in the SQL console with autocompletion, `explain`/`analyze` support and query telemetry
- **Run Drizzle queries** with the Drizzle runner
- **Explore and manage your schema** — tables, views, columns, indexes, foreign keys, policies and privileges

## Under the hood
At its core Drizzle Studio is a UI component which renders database content and gives you primitives to
manipulate both data and schema. Being written in TypeScript lets us plug it in basically everywhere
with zero friction:

![Drizzle Studio family — for infra, for platforms and for local development](@/assets/images/drizzle-studio-family.webp)

## Drizzle Studio for local development
This is the original one, where it all started — and as of today, it has 120K monthly users. It's meant to cover
your development needs on a local env: rapidly open a particular database and manage everything you need in there.

With the introduction of Schema Management, we started to deviate from the original schema in code first idea
towards a more conventional database browser, where the database itself is the source of truth.

It's free forever and grabs everything it needs from your
[drizzle.config.ts](/docs/drizzle-config-file) file. It supports `PostgreSQL`, `MySQL`, `SQLite`, `SingleStore`,
`MSSQL` and `CockroachDB`.

Install `drizzle-kit`, point it at your config and run `drizzle-kit studio` — the
[`drizzle-kit studio` docs](/docs/drizzle-kit-studio) walk through the setup, the `--port`, `--verbose`
and `--host` flags, and what to do about Safari and Brave blocking localhost.

The hosted version of Studio is meant for local development and is **not** meant to be exposed on a remote machine —
for that we have [Drizzle Gateway](#drizzle-gateway).

## Drizzle Gateway
[Drizzle Gateway](https://gateway.drizzle.team) is a free self-hosted Drizzle Studio on steroids.
It's a single Docker image (or a standalone binary) that connects to all your databases at once and lives in
your infrastructure like any other dockerised application — in your VPC, behind your bastion, with all the
benefits that come with it.

Unlike `drizzle-kit studio`, Gateway doesn't need a Drizzle project — you add database connections right in the UI,
keep them in a persistent volume, share it with your team and protect access with a master password
and per-user passcodes.

It was originally a paid service, but when Warhammer devs reached out to us we realised the friction of
it being paid just doesn't pay off, and eventually made it free. It's now at 350k container downloads
on the GitHub registry.

<a
  href="https://railway.com/new/template/drizzle-studio-gateway?referralCode=eobqmj&utm_medium=integration&utm_source=button&utm_campaign=drizzle-studio-gateway"
  target="_blank"
  rel="nofollow noreferrer"
  style="display: inline-block; margin: 16px 0;"
>
  <img src="https://railway.com/button.svg" alt="Deploy on Railway" width="183" height="40" />
</a>

```shell
# pull latest version
docker pull ghcr.io/drizzle-team/gateway:latest

# persistent volume is required for the configuration file
docker volume create drizzle-gateway

# start the gateway
docker run -d \
  --name drizzle-gateway \
  --restart always \
  -p 4983:4983 \
  -e PORT=4983 \
  -e MASTERPASS=your_master_password \
  -v drizzle-gateway:/app \
  ghcr.io/drizzle-team/gateway:latest
```

Once it's running, Gateway is available at `http://localhost:4983`. It works on both `arm` and `amd` architectures,
and standalone binaries are available for macOS and Linux — see [gateway.drizzle.team](https://gateway.drizzle.team)
for installation options and the changelog.

## Drizzle Studio Chrome extension
Our [Chrome extension](https://driz.link/extension) renders the database browser right on top of your
vendor's UI — no local setup, no connection strings. It's the thing you build when you can't get inside
a vendor's console the official way, but you use their product every day and desperately need a proper
in-place database browser.

It works with [PlanetScale](https://planetscale.com), [Cloudflare D1](https://developers.cloudflare.com/d1/) and [Vercel Postgres](https://vercel.com/docs/storage/vercel-postgres).

![Drizzle Studio button injected into the PlanetScale branches page](@/assets/images/drizzle-studio-extension-1.webp)

It's at ~3.3k weekly users, so it does seem people needed one.

We also have [sqlite.drizzle.studio](https://sqlite.drizzle.studio) to browse SQLite files right in your browser.

## Drizzle Studio Component
**Drizzle Studio Component** is our paid **B2B offering** — a pre-bundled, completely framework agnostic
and 100% secure web component of Drizzle Studio which you can embed into your UI —
`React` `Vue` `Svelte` `VanillaJS` etc.

It's an extremely powerful UI element that can elevate your offering if you provide Database as a SaaS
or data centric SaaS solutions based on SQL, and it works just as well for private non-customer facing
in-house usage.

It's highly customisable: we have an advanced [theming platform](https://drizzle.studio) where you can see
the component in your own colors before you talk to us, an opt-in SQL query runner and we can add various
partner-specific customisations on demand 👍

While Studio for local development is free forever and meant to just enrich the Drizzle ecosystem, this one
has been our main source of sustainable income — the one that fueled Drizzle open source development,
up until PlanetScale happened.

You might've already seen one in a database or agentic platform you use 👇

We also have a set of companies using embeddable Drizzle Studio for internal use cases.

Launch posts: [Neon](https://neon.tech/docs/changelog/2024-05-24) ·
[SQLite Cloud](https://blog.sqlitecloud.io/release-notes-introducing-database-studio-in-sqlite-cloud) ·
[Replit](https://blog.replit.com/database-editor) ·
[Deno](https://x.com/rough__sea/status/1950231545807327329) ·
[Create.xyz](https://x.com/create_xyz/status/1889479526499098830)

#### Interested?

You can read a detailed overview on npm — [@drizzle-team/studio](https://www.npmjs.com/package/@drizzle-team/studio)
is just a markdown file, there's nothing to install there. We're also around in DMs
on [Twitter](https://x.com/drizzleorm) and in the [Discord #drizzle-studio](https://driz.link/discord) channel.

## Drizzle Studio desktop app
Everything Studio does, as a native application — no terminal, no `drizzle-kit` invocation, just open it and
connect. It's in the works, and it's the one flavour you can't try yet.

Follow us on [Twitter](https://twitter.com/DrizzleORM) or join
[Discord #drizzle-studio-desktop](https://discord.com/channels/1043890932593987624/1504843464267796510)
to hear when it ships.

## FAQ
#### Is Drizzle Studio open source?
No. Drizzle ORM and Drizzle Kit are fully open sourced, while Studio is not.

Drizzle Studio for local development is free to use forever to enrich the Drizzle ecosystem,
open sourcing it would've broken our ability to provide B2B offerings and monetise it, unfortunately.

#### Can I deploy Studio to my VPS?
Yes — that's exactly what [Drizzle Gateway](#drizzle-gateway) is for. The hosted `local.drizzle.studio`
version is meant for local development only.

#### Does Studio send my data anywhere?
No. Both `drizzle-kit studio` and Gateway run the database connection on your machine or in your infrastructure,
your data never leaves it.

## What's next?
We ship Drizzle Studio updates every month — follow them on the [announcements](/announcements) page.

Subscribe on [Twitter](https://twitter.com/DrizzleORM) and welcome to our [Discord](https://driz.link/discord)!

