Skip to content

Commit

Permalink
Merge branch 'main' into smallserial-fix
Browse files Browse the repository at this point in the history
  • Loading branch information
AndriiSherman authored Sep 5, 2023
2 parents 4d52e1e + 0d378eb commit 6bb7596
Show file tree
Hide file tree
Showing 24 changed files with 2,563 additions and 28 deletions.
18 changes: 17 additions & 1 deletion drizzle-orm/src/aws-data-api/pg/session.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { ExecuteStatementCommandOutput, Field, RDSDataClient } from '@aws-sdk/client-rds-data';
import type { ColumnMetadata, ExecuteStatementCommandOutput, Field, RDSDataClient } from '@aws-sdk/client-rds-data';
import {
BeginTransactionCommand,
CommitTransactionCommand,
Expand Down Expand Up @@ -48,6 +48,7 @@ export class AwsDataApiPreparedQuery<T extends PreparedQueryConfig> extends Prep
resourceArn: options.resourceArn,
database: options.database,
transactionId,
includeResultMetadata: !fields && !customResultMapper,
});
}

Expand Down Expand Up @@ -80,6 +81,9 @@ export class AwsDataApiPreparedQuery<T extends PreparedQueryConfig> extends Prep
const { fields, rawQuery, client, customResultMapper } = this;
if (!fields && !customResultMapper) {
const result = await client.send(rawQuery);
if (result.columnMetadata && result.columnMetadata.length > 0) {
return this.mapResultRows(result.records ?? [], result.columnMetadata);
}
return result.records ?? [];
}

Expand All @@ -89,6 +93,18 @@ export class AwsDataApiPreparedQuery<T extends PreparedQueryConfig> extends Prep
return row.map((field: Field) => getValueFromDataApi(field));
});
}

/** @internal */
mapResultRows(records: Field[][], columnMetadata: ColumnMetadata[]) {
return records.map((record) => {
const row: Record<string, unknown> = {};
for (const [index, field] of record.entries()) {
const { name } = columnMetadata[index]!;
row[name ?? index] = getValueFromDataApi(field); // not what to default if name is undefined
}
return row;
});
}
}

export interface AwsDataApiSessionOptions {
Expand Down
6 changes: 5 additions & 1 deletion drizzle-orm/src/mysql-core/columns/datetime.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,12 @@ export class MySqlDateTime<T extends ColumnBaseConfig<'date', 'MySqlDateTime'>>
return `datetime${precision}`;
}

override mapToDriverValue(value: Date): unknown {
return value.toISOString().replace('T', ' ').replace('Z', '');
}

override mapFromDriverValue(value: string): Date {
return new Date(value);
return new Date(value.replace(' ', 'T') + 'Z');
}
}

Expand Down
4 changes: 2 additions & 2 deletions drizzle-orm/src/postgres-js/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,11 @@ pnpm add -D drizzle-kit
## Connection

```typescript
import { drizzle, PostgresJsDatabase } from 'drizzle-orm/postgres-js';
import { drizzle } from 'drizzle-orm/postgres-js';
import postgres from 'postgres';

const client = postgres(connectionString);
const db: PostgresJsDatabase = drizzle(client);
const db = drizzle(client);
```

See [main docs](/drizzle-orm/src/pg-core/README.md#sql-schema-declaration) for further usage.
Expand Down
210 changes: 186 additions & 24 deletions drizzle-orm/src/sql/expressions/conditions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,13 @@ import {

export function bindIfParam(value: unknown, column: SQLWrapper): SQLChunk {
if (
isDriverValueEncoder(column) && !isSQLWrapper(value) && !is(value, Param) && !is(value, Placeholder)
&& !is(value, Column) && !is(value, Table) && !is(value, View)
isDriverValueEncoder(column)
&& !isSQLWrapper(value)
&& !is(value, Param)
&& !is(value, Placeholder)
&& !is(value, Column)
&& !is(value, Table)
&& !is(value, View)
) {
return new Param(value, column);
}
Expand All @@ -29,10 +34,7 @@ export interface BinaryOperator {
left: TColumn,
right: GetColumnData<TColumn, 'raw'> | SQLWrapper,
): SQL;
<T>(
left: SQL.Aliased<T>,
right: T | SQLWrapper,
): SQL;
<T>(left: SQL.Aliased<T>, right: T | SQLWrapper): SQL;
<T extends SQLWrapper>(
left: Exclude<T, SQL.Aliased | Column>,
right: unknown,
Expand Down Expand Up @@ -100,8 +102,12 @@ export const ne: BinaryOperator = (left: SQLWrapper, right: unknown): SQL => {
* ```
*/
export function and(...conditions: (SQLWrapper | undefined)[]): SQL | undefined;
export function and(...unfilteredConditions: (SQLWrapper | undefined)[]): SQL | undefined {
const conditions = unfilteredConditions.filter((c): c is Exclude<typeof c, undefined> => c !== undefined);
export function and(
...unfilteredConditions: (SQLWrapper | undefined)[]
): SQL | undefined {
const conditions = unfilteredConditions.filter(
(c): c is Exclude<typeof c, undefined> => c !== undefined,
);

if (conditions.length === 0) {
return undefined;
Expand All @@ -111,7 +117,11 @@ export function and(...unfilteredConditions: (SQLWrapper | undefined)[]): SQL |
return new SQL(conditions);
}

return new SQL([new StringChunk('('), sql.join(conditions, new StringChunk(' and ')), new StringChunk(')')]);
return new SQL([
new StringChunk('('),
sql.join(conditions, new StringChunk(' and ')),
new StringChunk(')'),
]);
}

/**
Expand All @@ -131,8 +141,12 @@ export function and(...unfilteredConditions: (SQLWrapper | undefined)[]): SQL |
* ```
*/
export function or(...conditions: (SQLWrapper | undefined)[]): SQL | undefined;
export function or(...unfilteredConditions: (SQLWrapper | undefined)[]): SQL | undefined {
const conditions = unfilteredConditions.filter((c): c is Exclude<typeof c, undefined> => c !== undefined);
export function or(
...unfilteredConditions: (SQLWrapper | undefined)[]
): SQL | undefined {
const conditions = unfilteredConditions.filter(
(c): c is Exclude<typeof c, undefined> => c !== undefined,
);

if (conditions.length === 0) {
return undefined;
Expand All @@ -142,7 +156,11 @@ export function or(...unfilteredConditions: (SQLWrapper | undefined)[]): SQL | u
return new SQL(conditions);
}

return new SQL([new StringChunk('('), sql.join(conditions, new StringChunk(' or ')), new StringChunk(')')]);
return new SQL([
new StringChunk('('),
sql.join(conditions, new StringChunk(' or ')),
new StringChunk(')'),
]);
}

/**
Expand Down Expand Up @@ -315,13 +333,9 @@ export function notInArray(
column: SQLWrapper,
values: (unknown | Placeholder)[] | SQLWrapper,
): SQL {
if (isSQLWrapper(values)) {
return sql`${column} not in ${values}`;
}

if (Array.isArray(values)) {
if (values.length === 0) {
throw new Error('inArray requires at least one value');
throw new Error('notInArray requires at least one value');
}
return sql`${column} not in ${values.map((v) => bindIfParam(v, column))}`;
}
Expand Down Expand Up @@ -452,12 +466,13 @@ export function between<T extends SQLWrapper>(
min: unknown,
max: unknown,
): SQL;
export function between(
column: SQLWrapper,
min: unknown,
max: unknown,
): SQL {
return sql`${column} between ${bindIfParam(min, column)} and ${bindIfParam(max, column)}`;
export function between(column: SQLWrapper, min: unknown, max: unknown): SQL {
return sql`${column} between ${bindIfParam(min, column)} and ${
bindIfParam(
max,
column,
)
}`;
}

/**
Expand Down Expand Up @@ -497,7 +512,12 @@ export function notBetween(
min: unknown,
max: unknown,
): SQL {
return sql`${column} not between ${bindIfParam(min, column)} and ${bindIfParam(max, column)}`;
return sql`${column} not between ${
bindIfParam(
min,
column,
)
} and ${bindIfParam(max, column)}`;
}

/**
Expand Down Expand Up @@ -586,3 +606,145 @@ export function ilike(column: Column, value: string | SQLWrapper): SQL {
export function notIlike(column: Column, value: string | SQLWrapper): SQL {
return sql`${column} not ilike ${value}`;
}

/**
* Test that a column or expression contains all elements of
* the list passed as the second argument.
*
* ## Throws
*
* The argument passed in the second array can’t be empty:
* if an empty is provided, this method will throw.
*
* ## Examples
*
* ```ts
* // Select posts where its tags contain "Typescript" and "ORM".
* db.select().from(posts)
* .where(arrayContains(posts.tags, ['Typescript', 'ORM']))
* ```
*
* @see arrayContained to find if an array contains all elements of a column or expression
* @see arrayOverlaps to find if a column or expression contains any elements of an array
*/
export function arrayContains<T>(
column: SQL.Aliased<T>,
values: (T | Placeholder) | SQLWrapper,
): SQL;
export function arrayContains<TColumn extends Column>(
column: TColumn,
values: (GetColumnData<TColumn, 'raw'> | Placeholder) | SQLWrapper,
): SQL;
export function arrayContains<T extends SQLWrapper>(
column: Exclude<T, SQL.Aliased | Column>,
values: (unknown | Placeholder)[] | SQLWrapper,
): SQL;
export function arrayContains(
column: SQLWrapper,
values: (unknown | Placeholder)[] | SQLWrapper,
): SQL {
if (Array.isArray(values)) {
if (values.length === 0) {
throw new Error('arrayContains requires at least one value');
}
const array = sql`${bindIfParam(values, column)}`;
return sql`${column} @> ${array}`;
}

return sql`${column} @> ${bindIfParam(values, column)}`;
}

/**
* Test that the list passed as the second argument contains
* all elements of a column or expression.
*
* ## Throws
*
* The argument passed in the second array can’t be empty:
* if an empty is provided, this method will throw.
*
* ## Examples
*
* ```ts
* // Select posts where its tags contain "Typescript", "ORM" or both,
* // but filtering posts that have additional tags.
* db.select().from(posts)
* .where(arrayContained(posts.tags, ['Typescript', 'ORM']))
* ```
*
* @see arrayContains to find if a column or expression contains all elements of an array
* @see arrayOverlaps to find if a column or expression contains any elements of an array
*/
export function arrayContained<T>(
column: SQL.Aliased<T>,
values: (T | Placeholder) | SQLWrapper,
): SQL;
export function arrayContained<TColumn extends Column>(
column: TColumn,
values: (GetColumnData<TColumn, 'raw'> | Placeholder) | SQLWrapper,
): SQL;
export function arrayContained<T extends SQLWrapper>(
column: Exclude<T, SQL.Aliased | Column>,
values: (unknown | Placeholder)[] | SQLWrapper,
): SQL;
export function arrayContained(
column: SQLWrapper,
values: (unknown | Placeholder)[] | SQLWrapper,
): SQL {
if (Array.isArray(values)) {
if (values.length === 0) {
throw new Error('arrayContained requires at least one value');
}
const array = sql`${bindIfParam(values, column)}`;
return sql`${column} <@ ${array}`;
}

return sql`${column} <@ ${bindIfParam(values, column)}`;
}

/**
* Test that a column or expression contains any elements of
* the list passed as the second argument.
*
* ## Throws
*
* The argument passed in the second array can’t be empty:
* if an empty is provided, this method will throw.
*
* ## Examples
*
* ```ts
* // Select posts where its tags contain "Typescript", "ORM" or both.
* db.select().from(posts)
* .where(arrayOverlaps(posts.tags, ['Typescript', 'ORM']))
* ```
*
* @see arrayContains to find if a column or expression contains all elements of an array
* @see arrayContained to find if an array contains all elements of a column or expression
*/
export function arrayOverlaps<T>(
column: SQL.Aliased<T>,
values: (T | Placeholder) | SQLWrapper,
): SQL;
export function arrayOverlaps<TColumn extends Column>(
column: TColumn,
values: (GetColumnData<TColumn, 'raw'> | Placeholder) | SQLWrapper,
): SQL;
export function arrayOverlaps<T extends SQLWrapper>(
column: Exclude<T, SQL.Aliased | Column>,
values: (unknown | Placeholder)[] | SQLWrapper,
): SQL;
export function arrayOverlaps(
column: SQLWrapper,
values: (unknown | Placeholder)[] | SQLWrapper,
): SQL {
if (Array.isArray(values)) {
if (values.length === 0) {
throw new Error('arrayOverlaps requires at least one value');
}
const array = sql`${bindIfParam(values, column)}`;
return sql`${column} && ${array}`;
}

return sql`${column} && ${bindIfParam(values, column)}`;
}
Loading

0 comments on commit 6bb7596

Please sign in to comment.