Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Beta #2149

Merged
merged 46 commits into from
Apr 11, 2024
Merged

Beta #2149

Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
46 commits
Select commit Hold shift + click to select a range
c24e818
Add custom schema support to Postgres enums
dankochetov Mar 20, 2024
9e6a6ee
Add Xata credentials to branch pipeline
dankochetov Mar 20, 2024
139135c
Merge pull request #2048 from drizzle-team/enums-custom-schema
dankochetov Mar 20, 2024
5553513
fix: aws data api doesn't support savepoint name as variable
hugo082 Feb 28, 2024
5847889
fix: await for the savepoint to be executed
hugo082 Feb 28, 2024
4d3a50e
fix: await for transaction to be executed before releasing the savepoint
hugo082 Feb 28, 2024
6aea59b
fix: transaction id propagation
hugo082 Feb 28, 2024
21e118b
tests: fix transaction testing
hugo082 Feb 28, 2024
6a96c90
fix: AwsDataApiSession match PgSession api
hugo082 Feb 28, 2024
b3a1ec1
tests: fixes
hugo082 Feb 28, 2024
eaab7c7
Merge branch 'main' into main
hugo082 Mar 4, 2024
995647f
Merge branch 'main' into main
hugo082 Mar 8, 2024
3dc3691
Merge branch 'main' into main
hugo082 Mar 19, 2024
d3cdf21
Merge branch 'main' into main
hugo082 Mar 20, 2024
795b22c
Merge branch 'main' into main
hugo082 Mar 21, 2024
629bc9c
Add setWhere and targetWhere to on conflict clause in Postgres, fix w…
dankochetov Mar 22, 2024
35c8b2b
Fix query generation
dankochetov Mar 22, 2024
bb96a77
Merge pull request #2056 from drizzle-team/fix-onconflict-target-where
dankochetov Mar 22, 2024
c94bf32
Expose subquery config as API
dankochetov Mar 25, 2024
05c0ab3
Add missing awaits to Xata tests
dankochetov Mar 25, 2024
033da88
Fix async expect
dankochetov Mar 25, 2024
e2d2da4
Remove await
dankochetov Mar 25, 2024
ab9feb7
Fix error test
dankochetov Mar 25, 2024
085aaee
Merge branch 'main' into main
dankochetov Mar 27, 2024
f603677
Merge branch 'main' into main
hugo082 Mar 29, 2024
ddf43d6
Add batch to d1 migrator
AndriiSherman Apr 3, 2024
94e7af5
Check if there are any statements to batch
AndriiSherman Apr 4, 2024
4a2a2de
Migrate Data API tests to Vitest, update Data API result for raw queries
dankochetov Apr 6, 2024
9c30efd
Merge branch 'main' into aws-data-api-fixes
dankochetov Apr 6, 2024
df2bd77
Exclude SST from type checks
dankochetov Apr 6, 2024
9b8a94f
Merge branch 'beta' into aws-data-api-fixes
dankochetov Apr 7, 2024
a7c90b8
Merge pull request #2119 from drizzle-team/aws-data-api-fixes
dankochetov Apr 7, 2024
8e623f5
Merge branch 'beta' of github.com:drizzle-team/drizzle-orm into d1-batch
AndriiSherman Apr 8, 2024
be05767
Update release notes
AndriiSherman Apr 8, 2024
2c9b73b
Merge pull request #2137 from drizzle-team/d1-batch
AndriiSherman Apr 9, 2024
f25f1f4
Add array data-api workaround
livingforjesus Feb 21, 2024
1c0ee77
Add automatic casting for arrays with aws-data-api
livingforjesus Feb 21, 2024
34eeb4f
Update data-api driver code to use column
livingforjesus Feb 21, 2024
3349305
Added tests for insert and update arrays
livingforjesus Feb 21, 2024
1e3546b
Fix failing aws-data-api array related/adjacent
livingforjesus Feb 21, 2024
46b4593
Fixed broken tests in awsdataapi tests
livingforjesus Feb 21, 2024
bee3bcb
Merge branch 'beta' into fix-arrayvalue-issue
dankochetov Apr 10, 2024
defe5d8
Update tests
dankochetov Apr 10, 2024
338650d
Fix linter
dankochetov Apr 10, 2024
59f2958
Merge pull request #1911 from livingforjesus/fix-arrayvalue-issue
dankochetov Apr 10, 2024
1a48cee
Update changelog, bump ORM version
dankochetov Apr 10, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/workflows/release-feature-branch.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,7 @@ jobs:
PLANETSCALE_CONNECTION_STRING: ${{ secrets.PLANETSCALE_CONNECTION_STRING }}
NEON_CONNECTION_STRING: ${{ secrets.NEON_CONNECTION_STRING }}
XATA_API_KEY: ${{ secrets.XATA_API_KEY }}
XATA_BRANCH: ${{ secrets.XATA_BRANCH }}
LIBSQL_URL: file:local.db
run: |
if [[ ${{ github.event_name }} != "push" && "${{ github.event.pull_request.head.repo.full_name }}" != "${{ github.repository }}" ]]; then
Expand Down
16 changes: 16 additions & 0 deletions changelogs/drizzle-orm/0.30.8.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
- 🎉 Added custom schema support to enums in Postgres (fixes #669 via #2048):

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

const mySchema = pgSchema('mySchema');
const colors = mySchema.enum('colors', ['red', 'green', 'blue']);
```

- 🎉 Changed D1 `migrate()` function to use batch API (#2137)
- 🐛 Split `where` clause in Postgres `.onConflictDoUpdate` method into `setWhere` and `targetWhere` clauses, to support both `where` cases in `on conflict ...` clause (fixes #1628, #1302 via #2056)
- 🐛 Fixed query generation for `where` clause in Postgres `.onConflictDoNothing` method, as it was placed in a wrong spot (fixes #1628 via #2056)
- 🐛 Fixed multiple issues with AWS Data API driver (fixes #1931, #1932, #1934, #1936 via #2119)
- 🐛 Fix inserting and updating array values in AWS Data API (fixes #1912 via #1911)

Thanks @hugo082 and @livingforjesus!
3 changes: 2 additions & 1 deletion dprint.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@
"**/drizzle2/**/meta",
"**/*snapshot.json",
"**/_journal.json",
"**/tsup.config*.mjs"
"**/tsup.config*.mjs",
"**/.sst"
],
"plugins": [
"https://plugins.dprint.dev/typescript-0.83.0.wasm",
Expand Down
4 changes: 2 additions & 2 deletions drizzle-orm/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "drizzle-orm",
"version": "0.30.7",
"version": "0.30.8",
"description": "Drizzle ORM package for SQL databases",
"type": "module",
"scripts": {
Expand Down Expand Up @@ -147,7 +147,7 @@
}
},
"devDependencies": {
"@aws-sdk/client-rds-data": "^3.344.0",
"@aws-sdk/client-rds-data": "^3.549.0",
"@cloudflare/workers-types": "^4.20230904.0",
"@electric-sql/pglite": "^0.1.1",
"@libsql/client": "^0.5.6",
Expand Down
13 changes: 13 additions & 0 deletions drizzle-orm/src/aws-data-api/common/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,19 @@ export function getValueFromDataApi(field: Field) {
if (field.arrayValue.stringValues !== undefined) {
return field.arrayValue.stringValues;
}
if (field.arrayValue.longValues !== undefined) {
return field.arrayValue.longValues;
}
if (field.arrayValue.doubleValues !== undefined) {
return field.arrayValue.doubleValues;
}
if (field.arrayValue.booleanValues !== undefined) {
return field.arrayValue.booleanValues;
}
if (field.arrayValue.arrayValues !== undefined) {
return field.arrayValue.arrayValues;
}

throw new Error('Unknown array type');
} else {
throw new Error('Unknown type');
Expand Down
62 changes: 57 additions & 5 deletions drizzle-orm/src/aws-data-api/pg/driver.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,21 @@
import { entityKind } from '~/entity.ts';
import { entityKind, is } from '~/entity.ts';
import type { SQL, SQLWrapper } from '~/index.ts';
import { Param, sql, Table } from '~/index.ts';
import type { Logger } from '~/logger.ts';
import { DefaultLogger } from '~/logger.ts';
import { PgDatabase } from '~/pg-core/db.ts';
import { PgDialect } from '~/pg-core/dialect.ts';
import type { PgColumn, PgInsertConfig, PgTable, TableConfig } from '~/pg-core/index.ts';
import { PgArray } from '~/pg-core/index.ts';
import type { PgRaw } from '~/pg-core/query-builders/raw.ts';
import {
createTableRelationsHelpers,
extractTablesRelationalConfig,
type RelationalSchemaConfig,
type TablesRelationalConfig,
} from '~/relations.ts';
import type { DrizzleConfig } from '~/utils.ts';
import type { AwsDataApiClient, AwsDataApiPgQueryResultHKT } from './session.ts';
import type { DrizzleConfig, UpdateSet } from '~/utils.ts';
import type { AwsDataApiClient, AwsDataApiPgQueryResult, AwsDataApiPgQueryResultHKT } from './session.ts';
import { AwsDataApiSession } from './session.ts';

export interface PgDriverOptions {
Expand All @@ -28,16 +33,63 @@ export interface DrizzleAwsDataApiPgConfig<
secretArn: string;
}

export type AwsDataApiPgDatabase<
export class AwsDataApiPgDatabase<
TSchema extends Record<string, unknown> = Record<string, never>,
> = PgDatabase<AwsDataApiPgQueryResultHKT, TSchema>;
> extends PgDatabase<AwsDataApiPgQueryResultHKT, TSchema> {
static readonly [entityKind]: string = 'AwsDataApiPgDatabase';

override execute<
TRow extends Record<string, unknown> = Record<string, unknown>,
>(query: SQLWrapper): PgRaw<AwsDataApiPgQueryResult<TRow>> {
return super.execute(query);
}
}

export class AwsPgDialect extends PgDialect {
static readonly [entityKind]: string = 'AwsPgDialect';

override escapeParam(num: number): string {
return `:${num + 1}`;
}

override buildInsertQuery(
{ table, values, onConflict, returning }: PgInsertConfig<PgTable<TableConfig>>,
): SQL<unknown> {
const columns: Record<string, PgColumn> = table[Table.Symbol.Columns];
const colEntries: [string, PgColumn][] = Object.entries(columns);
for (const value of values) {
for (const [fieldName, col] of colEntries) {
const colValue = value[fieldName];
if (
is(colValue, Param) && colValue.value !== undefined && is(colValue.encoder, PgArray)
&& Array.isArray(colValue.value)
) {
value[fieldName] = sql`cast(${col.mapToDriverValue(colValue.value)} as ${
sql.raw(colValue.encoder.getSQLType())
})`;
}
}
}

return super.buildInsertQuery({ table, values, onConflict, returning });
}

override buildUpdateSet(table: PgTable<TableConfig>, set: UpdateSet): SQL<unknown> {
const columns: Record<string, PgColumn> = table[Table.Symbol.Columns];

for (const [colName, colValue] of Object.entries(set)) {
const currentColumn = columns[colName];
if (
currentColumn && is(colValue, Param) && colValue.value !== undefined && is(colValue.encoder, PgArray)
&& Array.isArray(colValue.value)
) {
set[colName] = sql`cast(${currentColumn?.mapToDriverValue(colValue.value)} as ${
sql.raw(colValue.encoder.getSQLType())
})`;
}
}
return super.buildUpdateSet(table, set);
}
}

export function drizzle<TSchema extends Record<string, unknown> = Record<string, never>>(
Expand Down
51 changes: 33 additions & 18 deletions drizzle-orm/src/aws-data-api/pg/session.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,13 +56,13 @@ export class AwsDataApiPreparedQuery<T extends PreparedQueryConfig> extends PgPr
async execute(placeholderValues: Record<string, unknown> | undefined = {}): Promise<T['execute']> {
const { fields, joinsNotNullableMap, customResultMapper } = this;

const rows = await this.values(placeholderValues) as unknown[][];
const result = await this.values(placeholderValues) as AwsDataApiPgQueryResult<unknown[]>;
if (!fields && !customResultMapper) {
return rows as T['execute'];
return result as T['execute'];
}
return customResultMapper
? customResultMapper(rows)
: rows.map((row) => mapResultRow<T['execute']>(fields!, row, joinsNotNullableMap));
? customResultMapper(result.rows!)
: result.rows!.map((row) => mapResultRow<T['execute']>(fields!, row, joinsNotNullableMap));
}

all(placeholderValues?: Record<string, unknown> | undefined): Promise<T['all']> {
Expand All @@ -83,16 +83,24 @@ export class AwsDataApiPreparedQuery<T extends PreparedQueryConfig> extends PgPr
if (!fields && !customResultMapper) {
const result = await client.send(rawQuery);
if (result.columnMetadata && result.columnMetadata.length > 0) {
return this.mapResultRows(result.records ?? [], result.columnMetadata);
const rows = this.mapResultRows(result.records ?? [], result.columnMetadata);
return {
...result,
rows,
};
}
return result.records ?? [];
return result;
}

const result = await client.send(rawQuery);
const rows = result.records?.map((row) => {
return row.map((field) => getValueFromDataApi(field));
}) ?? [];

return result.records?.map((row: any) => {
return row.map((field: Field) => getValueFromDataApi(field));
});
return {
...result,
rows,
};
}

/** @internal */
Expand Down Expand Up @@ -155,9 +163,10 @@ export class AwsDataApiSession<
prepareQuery<T extends PreparedQueryConfig = PreparedQueryConfig>(
query: QueryWithTypings,
fields: SelectedFieldsOrdered | undefined,
transactionId: string | undefined,
name: string | undefined,
isResponseInArrayMode: boolean,
customResultMapper?: (rows: unknown[][]) => T['execute'],
transactionId?: string,
): PgPreparedQuery<T> {
return new AwsDataApiPreparedQuery(
this.client,
Expand All @@ -166,7 +175,7 @@ export class AwsDataApiSession<
query.typings ?? [],
this.options,
fields,
transactionId,
transactionId ?? this.transactionId,
isResponseInArrayMode,
customResultMapper,
);
Expand All @@ -176,8 +185,10 @@ export class AwsDataApiSession<
return this.prepareQuery<PreparedQueryConfig & { execute: T }>(
this.dialect.sqlToQuery(query),
undefined,
this.transactionId,
undefined,
false,
undefined,
this.transactionId,
).execute();
}

Expand Down Expand Up @@ -208,21 +219,25 @@ export class AwsDataApiTransaction<
> extends PgTransaction<AwsDataApiPgQueryResultHKT, TFullSchema, TSchema> {
static readonly [entityKind]: string = 'AwsDataApiTransaction';

override transaction<T>(transaction: (tx: AwsDataApiTransaction<TFullSchema, TSchema>) => Promise<T>): Promise<T> {
override async transaction<T>(
transaction: (tx: AwsDataApiTransaction<TFullSchema, TSchema>) => Promise<T>,
): Promise<T> {
const savepointName = `sp${this.nestedIndex + 1}`;
const tx = new AwsDataApiTransaction(this.dialect, this.session, this.schema, this.nestedIndex + 1);
this.session.execute(sql`savepoint ${savepointName}`);
await this.session.execute(sql.raw(`savepoint ${savepointName}`));
try {
const result = transaction(tx);
this.session.execute(sql`release savepoint ${savepointName}`);
const result = await transaction(tx);
await this.session.execute(sql.raw(`release savepoint ${savepointName}`));
return result;
} catch (e) {
this.session.execute(sql`rollback to savepoint ${savepointName}`);
await this.session.execute(sql.raw(`rollback to savepoint ${savepointName}`));
throw e;
}
}
}

export type AwsDataApiPgQueryResult<T> = ExecuteStatementCommandOutput & { rows: T[] };

export interface AwsDataApiPgQueryResultHKT extends QueryResultHKT {
type: ExecuteStatementCommandOutput;
type: AwsDataApiPgQueryResult<any>;
}
2 changes: 1 addition & 1 deletion drizzle-orm/src/d1/driver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import { SQLiteD1Session } from './session.ts';
export class DrizzleD1Database<
TSchema extends Record<string, unknown> = Record<string, never>,
> extends BaseSQLiteDatabase<'async', D1Result, TSchema> {
static readonly [entityKind]: string = 'LibSQLDatabase';
static readonly [entityKind]: string = 'D1Database';

/** @internal */
declare readonly session: SQLiteD1Session<TSchema, ExtractTablesWithRelations<TSchema>>;
Expand Down
44 changes: 43 additions & 1 deletion drizzle-orm/src/d1/migrator.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,53 @@
import type { MigrationConfig } from '~/migrator.ts';
import { readMigrationFiles } from '~/migrator.ts';
import { sql } from '~/sql/sql.ts';
import type { DrizzleD1Database } from './driver.ts';

export async function migrate<TSchema extends Record<string, unknown>>(
db: DrizzleD1Database<TSchema>,
config: string | MigrationConfig,
) {
const migrations = readMigrationFiles(config);
await db.dialect.migrate(migrations, db.session, config);
const migrationsTable = config === undefined
? '__drizzle_migrations'
: typeof config === 'string'
? '__drizzle_migrations'
: config.migrationsTable ?? '__drizzle_migrations';

const migrationTableCreate = sql`
CREATE TABLE IF NOT EXISTS ${sql.identifier(migrationsTable)} (
id SERIAL PRIMARY KEY,
hash text NOT NULL,
created_at numeric
)
`;
await db.session.run(migrationTableCreate);

const dbMigrations = await db.values<[number, string, string]>(
sql`SELECT id, hash, created_at FROM ${sql.identifier(migrationsTable)} ORDER BY created_at DESC LIMIT 1`,
);

const lastDbMigration = dbMigrations[0] ?? undefined;

const statementToBatch = [];

for (const migration of migrations) {
if (!lastDbMigration || Number(lastDbMigration[2])! < migration.folderMillis) {
for (const stmt of migration.sql) {
statementToBatch.push(db.run(sql.raw(stmt)));
}

statementToBatch.push(
db.run(
sql`INSERT INTO ${sql.identifier(migrationsTable)} ("hash", "created_at") VALUES(${
sql.raw(`'${migration.hash}'`)
}, ${sql.raw(`${migration.folderMillis}`)})`,
),
);
}
}

if (statementToBatch.length > 0) {
await db.session.batch(statementToBatch);
}
}
2 changes: 1 addition & 1 deletion drizzle-orm/src/d1/session.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ export class SQLiteD1Session<
);
}

async batch<U extends BatchItem, T extends Readonly<[U, ...U[]]>>(queries: T) {
async batch<T extends BatchItem<'sqlite'>[] | readonly BatchItem<'sqlite'>[]>(queries: T) {
const preparedQueries: PreparedQuery[] = [];
const builtQueries: D1PreparedStatement[] = [];

Expand Down
6 changes: 3 additions & 3 deletions drizzle-orm/src/mysql-core/dialect.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import {
type TablesRelationalConfig,
} from '~/relations.ts';
import { Param, type QueryWithTypings, SQL, sql, type SQLChunk, View } from '~/sql/sql.ts';
import { Subquery, SubqueryConfig } from '~/subquery.ts';
import { Subquery } from '~/subquery.ts';
import { getTableName, Table } from '~/table.ts';
import { orderSelectedFields, type UpdateSet } from '~/utils.ts';
import { and, DrizzleError, eq, type Name, ViewBaseConfig } from '../index.ts';
Expand Down Expand Up @@ -88,7 +88,7 @@ export class MySqlDialect {

const withSqlChunks = [sql`with `];
for (const [i, w] of queries.entries()) {
withSqlChunks.push(sql`${sql.identifier(w[SubqueryConfig].alias)} as (${w[SubqueryConfig].sql})`);
withSqlChunks.push(sql`${sql.identifier(w._.alias)} as (${w._.sql})`);
if (i < queries.length - 1) {
withSqlChunks.push(sql`, `);
}
Expand Down Expand Up @@ -230,7 +230,7 @@ export class MySqlDialect {
is(f.field, Column)
&& getTableName(f.field.table)
!== (is(table, Subquery)
? table[SubqueryConfig].alias
? table._.alias
: is(table, MySqlViewBase)
? table[ViewBaseConfig].name
: is(table, SQL)
Expand Down
Loading