Skip to content

Commit

Permalink
Flip the default - make client.querySQL() return an object
Browse files Browse the repository at this point in the history
  • Loading branch information
1st1 committed Jan 28, 2025
1 parent 5aa921d commit 1673652
Showing 4 changed files with 42 additions and 23 deletions.
19 changes: 19 additions & 0 deletions docs/reference.rst
Original file line number Diff line number Diff line change
@@ -343,8 +343,27 @@ Client
Run a SQL query and return the results as an array.
This method **always** returns an array.

The array will contain the returned rows. By default, rows are
``Objects`` with columns addressable by name.

This can controlled with ``client.withSQLRowMode('array' | 'object')``
API.

This method takes optional query arguments.

Example:

.. code-block:: js
let vals = await client.querySQL(`SELECT 1 as foo`)
console.log(vals); // [{'foo': 1}]
vals = await client
.withSQLRowMode('array')
.querySQL(`SELECT 1 as foo`);
console.log(vals); // [[1]]
.. js:method:: transaction<T>( \
action: (tx: Transaction) => Promise<T> \
): Promise<T>
4 changes: 2 additions & 2 deletions packages/driver/src/codecs/record.ts
Original file line number Diff line number Diff line change
@@ -77,7 +77,7 @@ export class RecordCodec extends Codec implements ICodec {
const elemBuf = ReadBuffer.alloc();
const overload = ctx.getContainerOverload("_private_sql_row");

if (overload !== SQLRowObjectCodec) {
if (overload != null && overload !== SQLRowObjectCodec) {
const result: any[] = new Array(els);
for (let i = 0; i < els; i++) {
buf.discard(4); // reserved
@@ -91,7 +91,7 @@ export class RecordCodec extends Codec implements ICodec {
result[i] = val;
}

if (overload != null) {
if (overload !== SQLRowArrayCodec) {
return overload.fromDatabase(result, { names: this.names });
}

12 changes: 6 additions & 6 deletions packages/driver/src/options.ts
Original file line number Diff line number Diff line change
@@ -2,7 +2,7 @@ import * as errors from "./errors/index";
import { utf8Encoder } from "./primitives/buffer";
import type { Mutable } from "./typeutil";
import type { Codecs } from "./codecs/codecs";
import { SQLRowModeObject } from "./codecs/record";
import { SQLRowModeArray } from "./codecs/record";
import type { ReadonlyCodecMap, MutableCodecMap } from "./codecs/context";
import { CodecContext, NOOP_CODEC_CONTEXT } from "./codecs/context";

@@ -280,9 +280,9 @@ export class Options {

if (mergeOptions._dropSQLRowCodec && clone.codecs.has("sql_row")) {
// This is an optimization -- if "sql_row" is the only codec defined
// and it's set to "array mode", the we want the codec mapping to be
// and it's set to "object mode", the we want the codec mapping to be
// empty instead. Why? Empty codec mapping short circuits a lot of
// custom codec code, and array is the default behavior anyway.
// custom codec code, and object is the default behavior anyway.
(clone.codecs as MutableCodecMap).delete("sql_row");
}

@@ -334,10 +334,10 @@ export class Options {
}

withSQLRowMode(mode: "array" | "object"): Options {
if (mode === "array") {
if (mode === "object") {
return this._cloneWith({ _dropSQLRowCodec: true });
} else if (mode === "object") {
return this._cloneWith({ codecs: SQLRowModeObject });
} else if (mode === "array") {
return this._cloneWith({ codecs: SQLRowModeArray });
} else {
throw new errors.InterfaceError(`invalid mode=${mode}`);
}
30 changes: 15 additions & 15 deletions packages/driver/test/client.test.ts
Original file line number Diff line number Diff line change
@@ -2586,10 +2586,10 @@ if (getEdgeDBVersion().major >= 5) {

if (getEdgeDBVersion().major >= 6) {
test("querySQL", async () => {
let client = getClient();
let client = getClient().withSQLRowMode("array");

try {
let res = await client.querySQL("select 1");
let res = await client.querySQL("select 1 as c");
expect(JSON.stringify(res)).toEqual("[[1]]");

res = await client.querySQL("select 1 AS foo, 2 AS bar");
@@ -2606,8 +2606,8 @@ if (getEdgeDBVersion().major >= 6) {
let client = getClient();

try {
let res = await client.querySQL("select 1");
expect(JSON.stringify(res)).toEqual("[[1]]");
let res = await client.querySQL("select 1 as A");
expect(JSON.stringify(res)).toEqual('[{"a":1}]');

for (let i = 0; i < 2; i++) {
res = await client
@@ -2638,8 +2638,8 @@ if (getEdgeDBVersion().major >= 6) {
.querySQL("select 1 AS foo, 2 AS bar");
expect(JSON.stringify(res)).toEqual('[{"foo":1,"bar":2}]');

res = await client.querySQL("select 1 + $1::int8", [41]);
expect(JSON.stringify(res)).toEqual("[[42]]");
res = await client.querySQL('select 1 + $1::int8 as "B"', [41]);
expect(JSON.stringify(res)).toEqual('[{"B":42}]');
}
} finally {
await client.close();
@@ -2664,21 +2664,21 @@ if (getEdgeDBVersion().major >= 6) {
try {
await client.transaction(async (tx) => {
await tx.execute(`
CREATE TYPE ${typename} {
CREATE REQUIRED PROPERTY prop1 -> std::str;
};
`);
CREATE TYPE ${typename} {
CREATE REQUIRED PROPERTY prop1 -> std::str;
};
`);

await tx.executeSQL(`
INSERT INTO "${typename}" (prop1) VALUES (123);
`);
INSERT INTO "${typename}" (prop1) VALUES (123);
`);

let res = await tx.querySingle(query);
expect(res).toBe("123");

await tx.querySQL(`
UPDATE "${typename}" SET prop1 = '345';
`);
UPDATE "${typename}" SET prop1 = '345';
`);

res = await tx.querySingle(query);
expect(res).toBe("345");
@@ -2711,7 +2711,7 @@ if (getEdgeDBVersion().major >= 6) {
`select $1::${typename} as "val"`,
[val],
);
expect(JSON.stringify(res[0][0])).toEqual(JSON.stringify(val));
expect(JSON.stringify(res[0].val)).toEqual(JSON.stringify(val));
}
} finally {
await client.close();

0 comments on commit 1673652

Please sign in to comment.