Skip to content

Commit

Permalink
Add Prisma driver via extension
Browse files Browse the repository at this point in the history
  • Loading branch information
dankochetov committed Jun 8, 2024
1 parent 4ecfe1f commit 0b4d01d
Show file tree
Hide file tree
Showing 39 changed files with 5,143 additions and 1,942 deletions.
2 changes: 2 additions & 0 deletions .eslintignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,5 @@ examples
**/*.mjs
**/*.cjs
**/playground
integration-tests/tests/prisma/*/client
integration-tests/tests/prisma/*/drizzle
4 changes: 2 additions & 2 deletions .eslintrc.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ plugins:
- import
- unused-imports
- no-instanceof
- drizzle
- drizzle-internal
rules:
'@typescript-eslint/consistent-type-imports':
- error
Expand Down Expand Up @@ -61,7 +61,7 @@ rules:
'unicorn/relative-url-style': 'off'
'eqeqeq': 'error'
'no-instanceof/no-instanceof': 'error'
'drizzle/require-entity-kind': 'error'
'drizzle-internal/require-entity-kind': 'error'
'unicorn/prefer-string-replace-all': 'off'
'unicorn/no-process-exit': 'off'
'@typescript-eslint/ban-ts-comment': 'off'
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,4 @@ dist.new
.rollup.cache
dist-dts
rollup.config-*.mjs
.DS_Store
4 changes: 3 additions & 1 deletion dprint.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,9 @@
"**/*snapshot.json",
"**/_journal.json",
"**/tsup.config*.mjs",
"**/.sst"
"**/.sst",
"integration-tests/tests/prisma/*/client",
"integration-tests/tests/prisma/*/drizzle"
],
"plugins": [
"https://plugins.dprint.dev/typescript-0.83.0.wasm",
Expand Down
12 changes: 7 additions & 5 deletions drizzle-orm/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@
"@op-engineering/op-sqlite": ">=2",
"@opentelemetry/api": "^1.4.1",
"@planetscale/database": ">=1",
"@prisma/client": "*",
"@tidbcloud/serverless": "*",
"@types/better-sqlite3": "*",
"@types/pg": "*",
"@types/react": ">=18",
Expand All @@ -67,8 +69,7 @@
"postgres": ">=3",
"react": ">=18",
"sql.js": ">=1",
"sqlite3": ">=5",
"@tidbcloud/serverless": "*"
"sqlite3": ">=5"
},
"peerDependenciesMeta": {
"mysql2": {
Expand Down Expand Up @@ -160,6 +161,7 @@
"@opentelemetry/api": "^1.4.1",
"@originjs/vite-plugin-commonjs": "^1.0.3",
"@planetscale/database": "^1.16.0",
"@prisma/client": "5.14.0",
"@tidbcloud/serverless": "^0.1.1",
"@types/better-sqlite3": "^7.6.4",
"@types/node": "^20.2.5",
Expand All @@ -181,9 +183,9 @@
"sql.js": "^1.8.0",
"sqlite3": "^5.1.2",
"tslib": "^2.5.2",
"tsx": "^3.12.7",
"vite-tsconfig-paths": "^4.2.0",
"vitest": "^0.31.4",
"tsx": "^4.14.0",
"vite-tsconfig-paths": "^4.3.2",
"vitest": "^1.6.0",
"zod": "^3.20.2",
"zx": "^7.2.2"
}
Expand Down
15 changes: 8 additions & 7 deletions drizzle-orm/src/mysql-core/session.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,20 +28,21 @@ export interface PreparedQueryConfig {
iterator: unknown;
}

export interface PreparedQueryHKT {
export interface MySqlPreparedQueryHKT {
readonly $brand: 'MySqlPreparedQueryHKT';
readonly config: unknown;
readonly type: unknown;
}

export type PreparedQueryKind<
TKind extends PreparedQueryHKT,
TKind extends MySqlPreparedQueryHKT,
TConfig extends PreparedQueryConfig,
TAssume extends boolean = false,
> = Equal<TAssume, true> extends true ? Assume<(TKind & { readonly config: TConfig })['type'], PreparedQuery<TConfig>>
> = Equal<TAssume, true> extends true
? Assume<(TKind & { readonly config: TConfig })['type'], MySqlPreparedQuery<TConfig>>
: (TKind & { readonly config: TConfig })['type'];

export abstract class PreparedQuery<T extends PreparedQueryConfig> {
export abstract class MySqlPreparedQuery<T extends PreparedQueryConfig> {
static readonly [entityKind]: string = 'MySqlPreparedQuery';

/** @internal */
Expand All @@ -68,7 +69,7 @@ export abstract class MySqlSession<

constructor(protected dialect: MySqlDialect) {}

abstract prepareQuery<T extends PreparedQueryConfig, TPreparedQueryHKT extends PreparedQueryHKT>(
abstract prepareQuery<T extends PreparedQueryConfig, TPreparedQueryHKT extends MySqlPreparedQueryHKT>(
query: Query,
fields: SelectedFieldsOrdered | undefined,
customResultMapper?: (rows: unknown[][]) => T['execute'],
Expand Down Expand Up @@ -141,6 +142,6 @@ export abstract class MySqlTransaction<
): Promise<T>;
}

export interface PreparedQueryHKTBase extends PreparedQueryHKT {
type: PreparedQuery<Assume<this['config'], PreparedQueryConfig>>;
export interface PreparedQueryHKTBase extends MySqlPreparedQueryHKT {
type: MySqlPreparedQuery<Assume<this['config'], PreparedQueryConfig>>;
}
6 changes: 3 additions & 3 deletions drizzle-orm/src/mysql-proxy/session.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,13 @@ import type { MySqlDialect } from '~/mysql-core/dialect.ts';
import { MySqlTransaction } from '~/mysql-core/index.ts';
import type { SelectedFieldsOrdered } from '~/mysql-core/query-builders/select.types.ts';
import type {
MySqlPreparedQueryHKT,
MySqlTransactionConfig,
PreparedQueryConfig,
PreparedQueryHKT,
PreparedQueryKind,
QueryResultHKT,
} from '~/mysql-core/session.ts';
import { MySqlSession, PreparedQuery as PreparedQueryBase } from '~/mysql-core/session.ts';
import { MySqlPreparedQuery as PreparedQueryBase, MySqlSession } from '~/mysql-core/session.ts';
import type { RelationalSchemaConfig, TablesRelationalConfig } from '~/relations.ts';
import { fillPlaceholders } from '~/sql/sql.ts';
import type { Query, SQL } from '~/sql/sql.ts';
Expand Down Expand Up @@ -132,6 +132,6 @@ export interface MySqlRemoteQueryResultHKT extends QueryResultHKT {
type: MySqlRawQueryResult;
}

export interface MySqlRemotePreparedQueryHKT extends PreparedQueryHKT {
export interface MySqlRemotePreparedQueryHKT extends MySqlPreparedQueryHKT {
type: PreparedQuery<Assume<this['config'], PreparedQueryConfig>>;
}
8 changes: 4 additions & 4 deletions drizzle-orm/src/mysql2/session.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,12 @@ import type { MySqlDialect } from '~/mysql-core/dialect.ts';
import type { SelectedFieldsOrdered } from '~/mysql-core/query-builders/select.types.ts';
import {
type Mode,
MySqlPreparedQuery,
type MySqlPreparedQueryHKT,
MySqlSession,
MySqlTransaction,
type MySqlTransactionConfig,
PreparedQuery,
type PreparedQueryConfig,
type PreparedQueryHKT,
type PreparedQueryKind,
type QueryResultHKT,
} from '~/mysql-core/session.ts';
Expand All @@ -38,7 +38,7 @@ export type MySqlQueryResult<
T = any,
> = [T extends ResultSetHeader ? T : T[], FieldPacket[]];

export class MySql2PreparedQuery<T extends PreparedQueryConfig> extends PreparedQuery<T> {
export class MySql2PreparedQuery<T extends PreparedQueryConfig> extends MySqlPreparedQuery<T> {
static readonly [entityKind]: string = 'MySql2PreparedQuery';

private rawQuery: QueryOptions;
Expand Down Expand Up @@ -293,6 +293,6 @@ export interface MySql2QueryResultHKT extends QueryResultHKT {
type: MySqlRawQueryResult;
}

export interface MySql2PreparedQueryHKT extends PreparedQueryHKT {
export interface MySql2PreparedQueryHKT extends MySqlPreparedQueryHKT {
type: MySql2PreparedQuery<Assume<this['config'], PreparedQueryConfig>>;
}
10 changes: 5 additions & 5 deletions drizzle-orm/src/planetscale-serverless/session.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,18 @@ import { NoopLogger } from '~/logger.ts';
import type { MySqlDialect } from '~/mysql-core/dialect.ts';
import type { SelectedFieldsOrdered } from '~/mysql-core/query-builders/select.types.ts';
import {
MySqlPreparedQuery,
type MySqlPreparedQueryHKT,
MySqlSession,
MySqlTransaction,
PreparedQuery,
type PreparedQueryConfig,
type PreparedQueryHKT,
type QueryResultHKT,
} from '~/mysql-core/session.ts';
import type { RelationalSchemaConfig, TablesRelationalConfig } from '~/relations.ts';
import { fillPlaceholders, type Query, type SQL, sql } from '~/sql/sql.ts';
import { type Assume, mapResultRow } from '~/utils.ts';

export class PlanetScalePreparedQuery<T extends PreparedQueryConfig> extends PreparedQuery<T> {
export class PlanetScalePreparedQuery<T extends PreparedQueryConfig> extends MySqlPreparedQuery<T> {
static readonly [entityKind]: string = 'PlanetScalePreparedQuery';

private rawQuery = { as: 'object' } as const;
Expand Down Expand Up @@ -86,7 +86,7 @@ export class PlanetscaleSession<
query: Query,
fields: SelectedFieldsOrdered | undefined,
customResultMapper?: (rows: unknown[][]) => T['execute'],
): PreparedQuery<T> {
): MySqlPreparedQuery<T> {
return new PlanetScalePreparedQuery(this.client, query.sql, query.params, this.logger, fields, customResultMapper);
}

Expand Down Expand Up @@ -165,6 +165,6 @@ export interface PlanetscaleQueryResultHKT extends QueryResultHKT {
type: ExecutedQuery;
}

export interface PlanetScalePreparedQueryHKT extends PreparedQueryHKT {
export interface PlanetScalePreparedQueryHKT extends MySqlPreparedQueryHKT {
type: PlanetScalePreparedQuery<Assume<this['config'], PreparedQueryConfig>>;
}
43 changes: 43 additions & 0 deletions drizzle-orm/src/prisma/mysql/driver.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import type { PrismaClient } from '@prisma/client/extension';

import { Prisma } from '@prisma/client';

import { entityKind } from '~/entity';
import type { Logger } from '~/logger.ts';
import { DefaultLogger } from '~/logger.ts';
import type { QueryResultHKT } from '~/mysql-core';
import { MySqlDatabase, MySqlDialect } from '~/mysql-core';
import type { DrizzleConfig } from '~/utils.ts';
import type { PrismaMySqlPreparedQueryHKT } from './session';
import { PrismaMySqlSession } from './session';

export class PrismaMySqlDatabase
extends MySqlDatabase<QueryResultHKT, PrismaMySqlPreparedQueryHKT, Record<string, never>>
{
static readonly [entityKind]: string = 'PrismaMySqlDatabase';

constructor(client: PrismaClient, logger: Logger | undefined) {
const dialect = new MySqlDialect();
super(dialect, new PrismaMySqlSession(dialect, client, { logger }), undefined, 'default');
}
}

export type PrismaMySqlConfig = Omit<DrizzleConfig, 'schema'>;

export function drizzle(config: PrismaMySqlConfig = {}) {
let logger: Logger | undefined;
if (config.logger === true) {
logger = new DefaultLogger();
} else if (config.logger !== false) {
logger = config.logger;
}

return Prisma.defineExtension((client) => {
return client.$extends({
name: 'drizzle',
client: {
$drizzle: new PrismaMySqlDatabase(client, logger),
},
});
});
}
2 changes: 2 additions & 0 deletions drizzle-orm/src/prisma/mysql/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from './driver';
export * from './session';
81 changes: 81 additions & 0 deletions drizzle-orm/src/prisma/mysql/session.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
import type { PrismaClient } from '@prisma/client/extension';

import { entityKind } from '~/entity';
import { type Logger, NoopLogger } from '~/logger';
import type {
MySqlDialect,
MySqlPreparedQueryHKT,
MySqlTransaction,
MySqlTransactionConfig,
PreparedQueryConfig,
QueryResultHKT,
} from '~/mysql-core';
import { MySqlPreparedQuery, MySqlSession } from '~/mysql-core';
import { fillPlaceholders } from '~/sql';
import type { Query, SQL } from '~/sql';
import type { Assume } from '~/utils';

export class PrismaMySqlPreparedQuery<T> extends MySqlPreparedQuery<PreparedQueryConfig & { execute: T }> {
override iterator(_placeholderValues?: Record<string, unknown> | undefined): AsyncGenerator<unknown, any, unknown> {
throw new Error('Method not implemented.');
}
static readonly [entityKind]: string = 'PrismaMySqlPreparedQuery';

constructor(
private readonly prisma: PrismaClient,
private readonly query: Query,
private readonly logger: Logger,
) {
super();
}

override execute(placeholderValues?: Record<string, unknown>): Promise<T> {
const params = fillPlaceholders(this.query.params, placeholderValues ?? {});
this.logger.logQuery(this.query.sql, params);
return this.prisma.$queryRawUnsafe(this.query.sql, ...params);
}
}

export interface PrismaMySqlSessionOptions {
logger?: Logger;
}

export class PrismaMySqlSession extends MySqlSession {
static readonly [entityKind]: string = 'PrismaMySqlSession';

private readonly logger: Logger;

constructor(
dialect: MySqlDialect,
private readonly prisma: PrismaClient,
private readonly options: PrismaMySqlSessionOptions,
) {
super(dialect);
this.logger = options.logger ?? new NoopLogger();
}

override execute<T>(query: SQL): Promise<T> {
return this.prepareQuery<PreparedQueryConfig & { execute: T }>(this.dialect.sqlToQuery(query)).execute();
}

override all<T = unknown>(_query: SQL): Promise<T[]> {
throw new Error('Method not implemented.');
}

override prepareQuery<T extends PreparedQueryConfig = PreparedQueryConfig>(query: Query): MySqlPreparedQuery<T> {
return new PrismaMySqlPreparedQuery(this.prisma, query, this.logger);
}

override transaction<T>(
_transaction: (
tx: MySqlTransaction<QueryResultHKT, PrismaMySqlPreparedQueryHKT, Record<string, never>, Record<string, never>>,
) => Promise<T>,
_config?: MySqlTransactionConfig,
): Promise<T> {
throw new Error('Method not implemented.');
}
}

export interface PrismaMySqlPreparedQueryHKT extends MySqlPreparedQueryHKT {
type: PrismaMySqlPreparedQuery<Assume<this['config'], PreparedQueryConfig>>;
}
40 changes: 40 additions & 0 deletions drizzle-orm/src/prisma/pg/driver.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import type { PrismaClient } from '@prisma/client/extension';

import { Prisma } from '@prisma/client';

import { entityKind } from '~/entity';
import type { Logger } from '~/logger.ts';
import { DefaultLogger } from '~/logger.ts';
import type { QueryResultHKT } from '~/pg-core';
import { PgDatabase, PgDialect } from '~/pg-core';
import type { DrizzleConfig } from '~/utils.ts';
import { PrismaPgSession } from './session';

export class PrismaPgDatabase extends PgDatabase<QueryResultHKT, Record<string, never>> {
static readonly [entityKind]: string = 'PrismaPgDatabase';

constructor(client: PrismaClient, logger: Logger | undefined) {
const dialect = new PgDialect();
super(dialect, new PrismaPgSession(dialect, client, { logger }), undefined);
}
}

export type PrismaPgConfig = Omit<DrizzleConfig, 'schema'>;

export function drizzle(config: PrismaPgConfig = {}) {
let logger: Logger | undefined;
if (config.logger === true) {
logger = new DefaultLogger();
} else if (config.logger !== false) {
logger = config.logger;
}

return Prisma.defineExtension((client) => {
return client.$extends({
name: 'drizzle',
client: {
$drizzle: new PrismaPgDatabase(client, logger),
},
});
});
}
2 changes: 2 additions & 0 deletions drizzle-orm/src/prisma/pg/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from './driver';
export * from './session';
Loading

0 comments on commit 0b4d01d

Please sign in to comment.