diff --git a/api/src/DuckDBConnection.ts b/api/src/DuckDBConnection.ts index 226325a..a052b10 100644 --- a/api/src/DuckDBConnection.ts +++ b/api/src/DuckDBConnection.ts @@ -36,7 +36,7 @@ export class DuckDBConnection { public async run( sql: string, values?: DuckDBValue[] | Record, - types?: DuckDBType[] | Record + types?: DuckDBType[] | Record ): Promise { if (values) { const prepared = await this.prepare(sql); @@ -51,14 +51,14 @@ export class DuckDBConnection { public async runAndRead( sql: string, values?: DuckDBValue[] | Record, - types?: DuckDBType[] | Record + types?: DuckDBType[] | Record ): Promise { return new DuckDBResultReader(await this.run(sql, values, types)); } public async runAndReadAll( sql: string, values?: DuckDBValue[] | Record, - types?: DuckDBType[] | Record + types?: DuckDBType[] | Record ): Promise { const reader = new DuckDBResultReader(await this.run(sql, values, types)); await reader.readAll(); @@ -68,7 +68,7 @@ export class DuckDBConnection { sql: string, targetRowCount: number, values?: DuckDBValue[] | Record, - types?: DuckDBType[] | Record + types?: DuckDBType[] | Record ): Promise { const reader = new DuckDBResultReader(await this.run(sql, values, types)); await reader.readUntil(targetRowCount); @@ -77,7 +77,7 @@ export class DuckDBConnection { public async stream( sql: string, values?: DuckDBValue[] | Record, - types?: DuckDBType[] | Record + types?: DuckDBType[] | Record ): Promise { const prepared = await this.prepare(sql); if (values) { @@ -88,14 +88,14 @@ export class DuckDBConnection { public async streamAndRead( sql: string, values?: DuckDBValue[] | Record, - types?: DuckDBType[] | Record + types?: DuckDBType[] | Record ): Promise { return new DuckDBResultReader(await this.stream(sql, values, types)); } public async streamAndReadAll( sql: string, values?: DuckDBValue[] | Record, - types?: DuckDBType[] | Record + types?: DuckDBType[] | Record ): Promise { const reader = new DuckDBResultReader( await this.stream(sql, values, types) @@ -107,7 +107,7 @@ export class DuckDBConnection { sql: string, targetRowCount: number, values?: DuckDBValue[] | Record, - types?: DuckDBType[] | Record + types?: DuckDBType[] | Record ): Promise { const reader = new DuckDBResultReader( await this.stream(sql, values, types) @@ -118,7 +118,7 @@ export class DuckDBConnection { public async start( sql: string, values?: DuckDBValue[] | Record, - types?: DuckDBType[] | Record + types?: DuckDBType[] | Record ): Promise { const prepared = await this.prepare(sql); if (values) { @@ -129,7 +129,7 @@ export class DuckDBConnection { public async startStream( sql: string, values?: DuckDBValue[] | Record, - types?: DuckDBType[] | Record + types?: DuckDBType[] | Record ): Promise { const prepared = await this.prepare(sql); if (values) { diff --git a/api/src/DuckDBPreparedStatement.ts b/api/src/DuckDBPreparedStatement.ts index 8f70dcc..8ff572a 100644 --- a/api/src/DuckDBPreparedStatement.ts +++ b/api/src/DuckDBPreparedStatement.ts @@ -164,17 +164,28 @@ export class DuckDBPreparedStatement { createValue(type, value) ); } - public bind(values: DuckDBValue[] | Record, types?: DuckDBType[] | Record) { + public bind( + values: DuckDBValue[] | Record, + types?: DuckDBType[] | Record + ) { 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); } } } diff --git a/api/src/typeForValue.ts b/api/src/typeForValue.ts index f9d2f2a..540bd21 100644 --- a/api/src/typeForValue.ts +++ b/api/src/typeForValue.ts @@ -9,6 +9,7 @@ import { DOUBLE, DuckDBType, HUGEINT, + INTEGER, INTERVAL, LIST, MAP, @@ -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': diff --git a/api/test/api.test.ts b/api/test/api.test.ts index bdd52de..f86d241 100644 --- a/api/test/api.test.ts +++ b/api/test/api.test.ts @@ -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( + assertValues( chunk, 0, - DuckDBDoubleVector, + DuckDBIntegerVector, [42] ); assertValues( @@ -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( + assertValues( chunk, 0, - DuckDBDoubleVector, + DuckDBIntegerVector, [42] ); - assertValues( + assertValues( chunk, 1, + DuckDBDoubleVector, + [42.3] + ); + assertValues( + 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])] + ); } }); });