Skip to content

Commit

Permalink
Merge pull request #113 from duckdb/jray/bind-type-inference-improvem…
Browse files Browse the repository at this point in the history
…ents

bind type inference improvements
  • Loading branch information
jraymakers authored Jan 18, 2025
2 parents fff0e93 + e6c3a11 commit 99dc2b1
Show file tree
Hide file tree
Showing 4 changed files with 71 additions and 29 deletions.
20 changes: 10 additions & 10 deletions api/src/DuckDBConnection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ export class DuckDBConnection {
public async run(
sql: string,
values?: DuckDBValue[] | Record<string, DuckDBValue>,
types?: DuckDBType[] | Record<string, DuckDBType>
types?: DuckDBType[] | Record<string, DuckDBType | undefined>
): Promise<DuckDBMaterializedResult> {
if (values) {
const prepared = await this.prepare(sql);
Expand All @@ -51,14 +51,14 @@ export class DuckDBConnection {
public async runAndRead(
sql: string,
values?: DuckDBValue[] | Record<string, DuckDBValue>,
types?: DuckDBType[] | Record<string, DuckDBType>
types?: DuckDBType[] | Record<string, DuckDBType | undefined>
): Promise<DuckDBResultReader> {
return new DuckDBResultReader(await this.run(sql, values, types));
}
public async runAndReadAll(
sql: string,
values?: DuckDBValue[] | Record<string, DuckDBValue>,
types?: DuckDBType[] | Record<string, DuckDBType>
types?: DuckDBType[] | Record<string, DuckDBType | undefined>
): Promise<DuckDBResultReader> {
const reader = new DuckDBResultReader(await this.run(sql, values, types));
await reader.readAll();
Expand All @@ -68,7 +68,7 @@ export class DuckDBConnection {
sql: string,
targetRowCount: number,
values?: DuckDBValue[] | Record<string, DuckDBValue>,
types?: DuckDBType[] | Record<string, DuckDBType>
types?: DuckDBType[] | Record<string, DuckDBType | undefined>
): Promise<DuckDBResultReader> {
const reader = new DuckDBResultReader(await this.run(sql, values, types));
await reader.readUntil(targetRowCount);
Expand All @@ -77,7 +77,7 @@ export class DuckDBConnection {
public async stream(
sql: string,
values?: DuckDBValue[] | Record<string, DuckDBValue>,
types?: DuckDBType[] | Record<string, DuckDBType>
types?: DuckDBType[] | Record<string, DuckDBType | undefined>
): Promise<DuckDBResult> {
const prepared = await this.prepare(sql);
if (values) {
Expand All @@ -88,14 +88,14 @@ export class DuckDBConnection {
public async streamAndRead(
sql: string,
values?: DuckDBValue[] | Record<string, DuckDBValue>,
types?: DuckDBType[] | Record<string, DuckDBType>
types?: DuckDBType[] | Record<string, DuckDBType | undefined>
): Promise<DuckDBResultReader> {
return new DuckDBResultReader(await this.stream(sql, values, types));
}
public async streamAndReadAll(
sql: string,
values?: DuckDBValue[] | Record<string, DuckDBValue>,
types?: DuckDBType[] | Record<string, DuckDBType>
types?: DuckDBType[] | Record<string, DuckDBType | undefined>
): Promise<DuckDBResultReader> {
const reader = new DuckDBResultReader(
await this.stream(sql, values, types)
Expand All @@ -107,7 +107,7 @@ export class DuckDBConnection {
sql: string,
targetRowCount: number,
values?: DuckDBValue[] | Record<string, DuckDBValue>,
types?: DuckDBType[] | Record<string, DuckDBType>
types?: DuckDBType[] | Record<string, DuckDBType | undefined>
): Promise<DuckDBResultReader> {
const reader = new DuckDBResultReader(
await this.stream(sql, values, types)
Expand All @@ -118,7 +118,7 @@ export class DuckDBConnection {
public async start(
sql: string,
values?: DuckDBValue[] | Record<string, DuckDBValue>,
types?: DuckDBType[] | Record<string, DuckDBType>
types?: DuckDBType[] | Record<string, DuckDBType | undefined>
): Promise<DuckDBPendingResult> {
const prepared = await this.prepare(sql);
if (values) {
Expand All @@ -129,7 +129,7 @@ export class DuckDBConnection {
public async startStream(
sql: string,
values?: DuckDBValue[] | Record<string, DuckDBValue>,
types?: DuckDBType[] | Record<string, DuckDBType>
types?: DuckDBType[] | Record<string, DuckDBType | undefined>
): Promise<DuckDBPendingResult> {
const prepared = await this.prepare(sql);
if (values) {
Expand Down
17 changes: 14 additions & 3 deletions api/src/DuckDBPreparedStatement.ts
Original file line number Diff line number Diff line change
Expand Up @@ -164,17 +164,28 @@ export class DuckDBPreparedStatement {
createValue(type, value)
);
}
public bind(values: DuckDBValue[] | Record<string, DuckDBValue>, types?: DuckDBType[] | Record<string, DuckDBType>) {
public bind(
values: DuckDBValue[] | Record<string, DuckDBValue>,
types?: DuckDBType[] | Record<string, DuckDBType | undefined>
) {
if (Array.isArray(values)) {
const typesIsArray = Array.isArray(types);
for (let i = 0; i < values.length; i++) {
this.bindValue(i + 1, values[i], typesIsArray ? types[i] : typeForValue(values[i]));
this.bindValue(
i + 1,
values[i],
typesIsArray ? types[i] : typeForValue(values[i])
);
}
} else {
const typesIsRecord = types && !Array.isArray(types);
for (const key in values) {
const index = this.parameterIndex(key);
this.bindValue(index, values[key], typesIsRecord ? types[key] : typeForValue(values[key]));
let type = typesIsRecord ? types[key] : undefined;
if (type === undefined) {
type = typeForValue(values[key]);
}
this.bindValue(index, values[key], type);
}
}
}
Expand Down
7 changes: 6 additions & 1 deletion api/src/typeForValue.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {
DOUBLE,
DuckDBType,
HUGEINT,
INTEGER,
INTERVAL,
LIST,
MAP,
Expand Down Expand Up @@ -55,7 +56,11 @@ export function typeForValue(value: DuckDBValue): DuckDBType {
case 'boolean':
return BOOLEAN;
case 'number':
return DOUBLE;
if (Math.round(value) === value) {
return INTEGER;
} else {
return DOUBLE;
}
case 'bigint':
return HUGEINT;
case 'string':
Expand Down
56 changes: 41 additions & 15 deletions api/test/api.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -485,19 +485,19 @@ describe('api', () => {
prepared.bind([42, 'duck', listValue([10, 11, 12])]);
const result = await prepared.run();
assertColumns(result, [
{ name: 'a', type: DOUBLE },
{ name: 'a', type: INTEGER },
{ name: 'b', type: VARCHAR },
{ name: 'c', type: LIST(DOUBLE) },
{ name: 'c', type: LIST(INTEGER) },
]);
const chunk = await result.fetchChunk();
assert.isDefined(chunk);
if (chunk) {
assert.strictEqual(chunk.columnCount, 3);
assert.strictEqual(chunk.rowCount, 1);
assertValues<number, DuckDBDoubleVector>(
assertValues<number, DuckDBIntegerVector>(
chunk,
0,
DuckDBDoubleVector,
DuckDBIntegerVector,
[42]
);
assertValues<string, DuckDBVarCharVector>(
Expand All @@ -518,42 +518,68 @@ describe('api', () => {
test('should support prepare statement bind with object', async () => {
await withConnection(async (connection) => {
const prepared = await connection.prepare(
'select $a as a, $b as b, $c as c'
'select $a as a, $b as b, $c as c, $d as d, $e as e, $f as f'
);
prepared.bind({
a: 42,
b: 'duck',
c: listValue([10, 11, 12]),
b: 42.3,
c: 'duck',
d: listValue([10, 11, 12]),
e: arrayValue([10.1, 11.2, 12.3]),
f: arrayValue([10, 11, 12]),
}, {
f: ARRAY(FLOAT, 2),
});
const result = await prepared.run();
assertColumns(result, [
{ name: 'a', type: DOUBLE },
{ name: 'b', type: VARCHAR },
{ name: 'c', type: LIST(DOUBLE) },
{ name: 'a', type: INTEGER },
{ name: 'b', type: DOUBLE },
{ name: 'c', type: VARCHAR },
{ name: 'd', type: LIST(INTEGER) },
{ name: 'e', type: ARRAY(DOUBLE, 3) },
{ name: 'f', type: ARRAY(FLOAT, 3) },
]);
const chunk = await result.fetchChunk();
assert.isDefined(chunk);
if (chunk) {
assert.strictEqual(chunk.columnCount, 3);
assert.strictEqual(chunk.columnCount, 6);
assert.strictEqual(chunk.rowCount, 1);
assertValues<number, DuckDBDoubleVector>(
assertValues<number, DuckDBIntegerVector>(
chunk,
0,
DuckDBDoubleVector,
DuckDBIntegerVector,
[42]
);
assertValues<string, DuckDBVarCharVector>(
assertValues<number, DuckDBDoubleVector>(
chunk,
1,
DuckDBDoubleVector,
[42.3]
);
assertValues<string, DuckDBVarCharVector>(
chunk,
2,
DuckDBVarCharVector,
['duck']
);
assertValues(
chunk,
2,
3,
DuckDBListVector,
[listValue([10, 11, 12])]
);
assertValues(
chunk,
4,
DuckDBArrayVector,
[arrayValue([10.1, 11.2, 12.3])]
);
assertValues(
chunk,
5,
DuckDBArrayVector,
[arrayValue([10, 11, 12])]
);
}
});
});
Expand Down

0 comments on commit 99dc2b1

Please sign in to comment.