Skip to content

Commit c061993

Browse files
committed
feat: add option to disable parsing JSON, remove redundant enableCallback from Statement
1 parent 2f85f3d commit c061993

File tree

4 files changed

+27
-33
lines changed

4 files changed

+27
-33
lines changed

doc.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,8 @@ pass `create: false` in the options.
1515
- `memory: boolean` - Whether to open the database in memory. Defaults to
1616
`false`.
1717
- `int64: boolean` - Whether to support BigInt columns. False by default, which
18-
means integers larger than 32 bit will be inaccurate.
18+
means integers larger than 32 bit will be inaccurate. Causes mixed values to
19+
be returned like `number | bigint`.
1920
- `flags: number` - Raw flags to pass to the C API. Normally you don't need
2021
this. Passing this ignores all other options.
2122
- `unsafeConcurrency: boolean` - Enable optimizations that will affect
@@ -24,6 +25,7 @@ pass `create: false` in the options.
2425
- `enableLoadExtension: boolean` - Enables the loading of SQLite extensions from
2526
a dynamic library, this needs to be set to true for the method `loadExtension`
2627
to work. Defaults to `false`.
28+
- `parseJson: boolean` - Enables parsing JSON. True by default.
2729

2830
### Usage
2931

src/database.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@ export interface DatabaseOpenOptions {
3535
unsafeConcurrency?: boolean;
3636
/** Enable or disable extension loading */
3737
enableLoadExtension?: boolean;
38+
/** Whether to parse JSON columns as JS objects. True by default. */
39+
parseJson?: boolean;
3840
}
3941

4042
/** Transaction function created using `Database#transaction`. */
@@ -153,6 +155,9 @@ export class Database {
153155
/** Whether to support BigInt columns. False by default, integers larger than 32 bit will be inaccurate. */
154156
int64: boolean;
155157

158+
/** Whether to parse JSON columns as JS objects. True by default. */
159+
parseJson: boolean;
160+
156161
unsafeConcurrency: boolean;
157162

158163
/** Whether DB connection is open */
@@ -214,6 +219,7 @@ export class Database {
214219
this.#path = path instanceof URL ? fromFileUrl(path) : path;
215220
let flags = 0;
216221
this.int64 = options.int64 ?? false;
222+
this.parseJson = options.parseJson ?? true;
217223
this.unsafeConcurrency = options.unsafeConcurrency ?? false;
218224
if (options.flags !== undefined) {
219225
flags = options.flags;

src/statement.ts

Lines changed: 18 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,12 @@ const JSON_SUBTYPE = 74;
7777

7878
const BIG_MAX = BigInt(Number.MAX_SAFE_INTEGER);
7979

80-
function getColumn(handle: Deno.PointerValue, i: number, int64: boolean): any {
80+
function getColumn(
81+
handle: Deno.PointerValue,
82+
i: number,
83+
int64: boolean,
84+
parseJson: boolean,
85+
): any {
8186
const ty = sqlite3_column_type(handle, i);
8287

8388
if (ty === SQLITE_INTEGER && !int64) return sqlite3_column_int(handle, i);
@@ -89,7 +94,7 @@ function getColumn(handle: Deno.PointerValue, i: number, int64: boolean): any {
8994
const text = readCstr(ptr, 0);
9095
const value = sqlite3_column_value(handle, i);
9196
const subtype = sqlite3_value_subtype(value);
92-
if (subtype === JSON_SUBTYPE) {
97+
if (subtype === JSON_SUBTYPE && parseJson) {
9398
try {
9499
return JSON.parse(text);
95100
} catch (_error) {
@@ -142,16 +147,6 @@ export class Statement<TStatement extends object = Record<string, any>> {
142147
#hasNoArgs = false;
143148
#unsafeConcurrency;
144149

145-
/**
146-
* Whether the query might call into JavaScript or not.
147-
*
148-
* Must enable if the query makes use of user defined functions,
149-
* otherwise there can be V8 crashes.
150-
*
151-
* Off by default. Causes performance degradation.
152-
*/
153-
callback = false;
154-
155150
/** Unsafe Raw (pointer) to the sqlite object */
156151
get unsafeHandle(): Deno.PointerValue {
157152
return this.#handle;
@@ -233,12 +228,6 @@ export class Statement<TStatement extends object = Record<string, any>> {
233228
}
234229
}
235230

236-
/** Shorthand for `this.callback = true`. Enables calling user defined functions. */
237-
enableCallback(): this {
238-
this.callback = true;
239-
return this;
240-
}
241-
242231
/** Get bind parameter name by index */
243232
bindParameterName(i: number): string {
244233
return readCstr(sqlite3_bind_parameter_name(this.#handle, i)!);
@@ -437,7 +426,7 @@ export class Statement<TStatement extends object = Record<string, any>> {
437426
return function(h) {
438427
return [${
439428
Array.from({ length: columnCount }).map((_, i) =>
440-
`getColumn(h, ${i}, ${this.db.int64})`
429+
`getColumn(h, ${i}, ${this.db.int64}, ${this.db.parseJson})`
441430
)
442431
.join(", ")
443432
}];
@@ -470,7 +459,7 @@ export class Statement<TStatement extends object = Record<string, any>> {
470459
return function(h) {
471460
return [${
472461
Array.from({ length: columnCount }).map((_, i) =>
473-
`getColumn(h, ${i}, ${this.db.int64})`
462+
`getColumn(h, ${i}, ${this.db.int64}, ${this.db.parseJson})`
474463
)
475464
.join(", ")
476465
}];
@@ -504,7 +493,7 @@ export class Statement<TStatement extends object = Record<string, any>> {
504493
return {
505494
${
506495
columnNames.map((name, i) =>
507-
`"${name}": getColumn(h, ${i}, ${this.db.int64})`
496+
`"${name}": getColumn(h, ${i}, ${this.db.int64}, ${this.db.parseJson})`
508497
).join(",\n")
509498
}
510499
};
@@ -562,6 +551,7 @@ export class Statement<TStatement extends object = Record<string, any>> {
562551
): T | undefined {
563552
const handle = this.#handle;
564553
const int64 = this.db.int64;
554+
const parseJson = this.db.parseJson;
565555
const arr = new Array(sqlite3_column_count(handle));
566556
sqlite3_reset(handle);
567557
if (!this.#hasNoArgs && !this.#bound) {
@@ -580,7 +570,7 @@ export class Statement<TStatement extends object = Record<string, any>> {
580570

581571
if (status === SQLITE3_ROW) {
582572
for (let i = 0; i < arr.length; i++) {
583-
arr[i] = getColumn(handle, i, int64);
573+
arr[i] = getColumn(handle, i, int64, parseJson);
584574
}
585575
sqlite3_reset(this.#handle);
586576
return arr as T;
@@ -594,13 +584,14 @@ export class Statement<TStatement extends object = Record<string, any>> {
594584
#valueNoArgs<T extends Array<unknown>>(): T | undefined {
595585
const handle = this.#handle;
596586
const int64 = this.db.int64;
587+
const parseJson = this.db.parseJson;
597588
const cc = sqlite3_column_count(handle);
598589
const arr = new Array(cc);
599590
sqlite3_reset(handle);
600591
const status = sqlite3_step(handle);
601592
if (status === SQLITE3_ROW) {
602593
for (let i = 0; i < cc; i++) {
603-
arr[i] = getColumn(handle, i, int64);
594+
arr[i] = getColumn(handle, i, int64, parseJson);
604595
}
605596
sqlite3_reset(this.#handle);
606597
return arr as T;
@@ -636,7 +627,7 @@ export class Statement<TStatement extends object = Record<string, any>> {
636627
): T | undefined {
637628
const handle = this.#handle;
638629
const int64 = this.db.int64;
639-
630+
const parseJson = this.db.parseJson;
640631
const columnNames = this.columnNames();
641632

642633
const row: Record<string, unknown> = {};
@@ -657,7 +648,7 @@ export class Statement<TStatement extends object = Record<string, any>> {
657648

658649
if (status === SQLITE3_ROW) {
659650
for (let i = 0; i < columnNames.length; i++) {
660-
row[columnNames[i]] = getColumn(handle, i, int64);
651+
row[columnNames[i]] = getColumn(handle, i, int64, parseJson);
661652
}
662653
sqlite3_reset(this.#handle);
663654
return row as T;
@@ -671,13 +662,14 @@ export class Statement<TStatement extends object = Record<string, any>> {
671662
#getNoArgs<T extends object>(): T | undefined {
672663
const handle = this.#handle;
673664
const int64 = this.db.int64;
665+
const parseJson = this.db.parseJson;
674666
const columnNames = this.columnNames();
675667
const row: Record<string, unknown> = this.#rowObject;
676668
sqlite3_reset(handle);
677669
const status = sqlite3_step(handle);
678670
if (status === SQLITE3_ROW) {
679671
for (let i = 0; i < columnNames?.length; i++) {
680-
row[columnNames[i]] = getColumn(handle, i, int64);
672+
row[columnNames[i]] = getColumn(handle, i, int64, parseJson);
681673
}
682674
sqlite3_reset(handle);
683675
return row as T;

test/test.ts

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -461,19 +461,16 @@ Deno.test("sqlite", async (t) => {
461461
await t.step("test functions", () => {
462462
const [result] = db
463463
.prepare("select deno_add(?, ?)")
464-
.enableCallback()
465464
.value<[number]>(1, 2)!;
466465
assertEquals(result, 3);
467466

468467
const [result2] = db
469468
.prepare("select deno_uppercase(?)")
470-
.enableCallback()
471469
.value<[string]>("hello")!;
472470
assertEquals(result2, "HELLO");
473471

474472
const [result3] = db
475473
.prepare("select deno_buffer_add_1(?)")
476-
.enableCallback()
477474
.value<[Uint8Array]>(new Uint8Array([1, 2, 3]))!;
478475
assertEquals(result3, new Uint8Array([2, 3, 4]));
479476

@@ -485,13 +482,11 @@ Deno.test("sqlite", async (t) => {
485482

486483
const [result5] = db
487484
.prepare("select regexp(?, ?)")
488-
.enableCallback()
489485
.value<[number]>("hello", "h.*")!;
490486
assertEquals(result5, 1);
491487

492488
const [result6] = db
493489
.prepare("select regexp(?, ?)")
494-
.enableCallback()
495490
.value<[number]>("hello", "x.*")!;
496491
assertEquals(result6, 0);
497492

@@ -501,7 +496,6 @@ Deno.test("sqlite", async (t) => {
501496
db.exec("insert into aggr_test (value) values (3)");
502497

503498
const stmt = db.prepare("select deno_sum_2x(value) from aggr_test");
504-
stmt.callback = true;
505499
const [result7] = stmt.value<[number]>()!;
506500
assertEquals(result7, 12);
507501
// Releases lock from table.

0 commit comments

Comments
 (0)