Skip to content

Commit cf13671

Browse files
feat(sql.array) add support to sql.array (#22946)
### What does this PR do? Fixes #17030 In this case should work as expected just passing a normal array should be serialized as JSON/JSONB Fixes #17798 Insert and update helpers should work as expected here when using sql.array helper: ```sql CREATE TABLE user ( id SERIAL PRIMARY KEY, name VARCHAR NOT NULL, roles TEXT[] ); ``` ```js const item = { id: 1, name: "test", role: sql.array(['a', 'b'], "TEXT") }; await sql` UPDATE user SET ${sql(item)} WHERE id = 1 `; ``` Fixes #22281 Should work using sql.array(array, "TEXT") Fixes #22165 Fixes #22155 Add sql.array(array, typeNameOrTypeID) in Bun.SQL (#15088) ### How did you verify your code works? Tests --------- Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
1 parent 5a12175 commit cf13671

File tree

7 files changed

+690
-11
lines changed

7 files changed

+690
-11
lines changed

packages/bun-types/sql.d.ts

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,68 @@ declare module "bun" {
1212
release(): void;
1313
}
1414

15+
type ArrayType =
16+
| "BOOLEAN"
17+
| "BYTEA"
18+
| "CHAR"
19+
| "NAME"
20+
| "TEXT"
21+
| "CHAR"
22+
| "VARCHAR"
23+
| "SMALLINT"
24+
| "INT2VECTOR"
25+
| "INTEGER"
26+
| "INT"
27+
| "BIGINT"
28+
| "REAL"
29+
| "DOUBLE PRECISION"
30+
| "NUMERIC"
31+
| "MONEY"
32+
| "OID"
33+
| "TID"
34+
| "XID"
35+
| "CID"
36+
| "JSON"
37+
| "JSONB"
38+
| "JSONPATH"
39+
| "XML"
40+
| "POINT"
41+
| "LSEG"
42+
| "PATH"
43+
| "BOX"
44+
| "POLYGON"
45+
| "LINE"
46+
| "CIRCLE"
47+
| "CIDR"
48+
| "MACADDR"
49+
| "INET"
50+
| "MACADDR8"
51+
| "DATE"
52+
| "TIME"
53+
| "TIMESTAMP"
54+
| "TIMESTAMPTZ"
55+
| "INTERVAL"
56+
| "TIMETZ"
57+
| "BIT"
58+
| "VARBIT"
59+
| "ACLITEM"
60+
| "PG_DATABASE"
61+
| (string & {});
62+
63+
/**
64+
* Represents a SQL array parameter
65+
*/
66+
interface SQLArrayParameter {
67+
/**
68+
* The serialized values of the array parameter
69+
*/
70+
serializedValues: string;
71+
/**
72+
* The type of the array parameter
73+
*/
74+
arrayType: ArrayType;
75+
}
76+
1577
/**
1678
* Represents a client within a transaction context Extends SQL with savepoint
1779
* functionality
@@ -630,6 +692,21 @@ declare module "bun" {
630692
*/
631693
reserve(): Promise<ReservedSQL>;
632694

695+
/**
696+
* Creates a new SQL array parameter
697+
* @param values - The values to create the array parameter from
698+
* @param typeNameOrTypeID - The type name or type ID to create the array parameter from, if omitted it will default to JSON
699+
* @returns A new SQL array parameter
700+
*
701+
* @example
702+
* ```ts
703+
* const array = sql.array([1, 2, 3], "INT");
704+
* await sql`CREATE TABLE users_posts (user_id INT, posts_id INT[])`;
705+
* await sql`INSERT INTO users_posts (user_id, posts_id) VALUES (${user.id}, ${array})`;
706+
* ```
707+
*/
708+
array(values: any[], typeNameOrTypeID?: number | ArrayType): SQLArrayParameter;
709+
633710
/**
634711
* Begins a new transaction.
635712
*

src/js/bun/sql.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -316,6 +316,7 @@ const SQL: typeof Bun.SQL = function SQL(
316316
// reserve is allowed to be called inside reserved connection but will return a new reserved connection from the pool
317317
// this matchs the behavior of the postgres package
318318
reserved_sql.reserve = () => sql.reserve();
319+
reserved_sql.array = sql.array;
319320
function onTransactionFinished(transaction_promise: Promise<any>) {
320321
reservedTransaction.delete(transaction_promise);
321322
}
@@ -590,6 +591,7 @@ const SQL: typeof Bun.SQL = function SQL(
590591
// reserve is allowed to be called inside transaction connection but will return a new reserved connection from the pool and will not be part of the transaction
591592
// this matchs the behavior of the postgres package
592593
transaction_sql.reserve = () => sql.reserve();
594+
transaction_sql.array = sql.array;
593595

594596
transaction_sql.connect = () => {
595597
if (state.connectionState & ReservedConnectionState.closed) {
@@ -829,6 +831,10 @@ const SQL: typeof Bun.SQL = function SQL(
829831
pool.connect(onReserveConnected.bind(promiseWithResolvers), true);
830832
return promiseWithResolvers.promise;
831833
};
834+
835+
sql.array = (values: any[], typeNameOrID: number | string | undefined = undefined) => {
836+
return pool.array(values, typeNameOrID);
837+
};
832838
sql.rollbackDistributed = async function (name: string) {
833839
if (pool.closed) {
834840
throw pool.connectionClosedError();
@@ -964,6 +970,10 @@ defaultSQLObject.reserve = (...args) => {
964970
ensureDefaultSQL();
965971
return lazyDefaultSQL.reserve(...args);
966972
};
973+
defaultSQLObject.array = (...args) => {
974+
ensureDefaultSQL();
975+
return lazyDefaultSQL.array(...args);
976+
};
967977
defaultSQLObject.commitDistributed = (...args) => {
968978
ensureDefaultSQL();
969979
return lazyDefaultSQL.commitDistributed(...args);

src/js/internal/sql/mysql.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import type { MySQLErrorOptions } from "internal/sql/errors";
22
import type { Query } from "./query";
3-
import type { DatabaseAdapter, SQLHelper, SQLResultArray, SSLMode } from "./shared";
3+
import type { ArrayType, DatabaseAdapter, SQLArrayParameter, SQLHelper, SQLResultArray, SSLMode } from "./shared";
44
const { SQLHelper, SSLMode, SQLResultArray } = require("internal/sql/shared");
55
const {
66
Query,
@@ -549,7 +549,9 @@ class MySQLAdapter
549549
connection.queries.delete(handler);
550550
}
551551
}
552-
552+
array(_values: any[], _typeNameOrID?: number | ArrayType): SQLArrayParameter {
553+
throw new Error("MySQL doesn't support arrays");
554+
}
553555
getTransactionCommands(options?: string): import("./shared").TransactionCommands {
554556
let BEGIN = "START TRANSACTION";
555557
if (options) {

0 commit comments

Comments
 (0)