Skip to content

Commit 6d34f4b

Browse files
authored
Merge pull request #37 from duckdb/jray/data-type-to-string
data type toString
2 parents d59bc93 + c908c5d commit 6d34f4b

File tree

5 files changed

+104
-3
lines changed

5 files changed

+104
-3
lines changed

api/pkgs/@duckdb/node-api/README.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,12 @@ function typeToString(dataType) {
191191
}
192192
```
193193

194+
While the example above demonstrates how to access the properties of data type objects, there is a much simpler way to convert them to strings:
195+
196+
```ts
197+
const dataTypeString = dataType.toString();
198+
```
199+
194200
### Inspect Data Values
195201

196202
```ts

api/src/DuckDBType.ts

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,14 @@
11
import { DuckDBTypeId } from './DuckDBTypeId';
2+
import { quotedIdentifier, quotedString } from './sql';
23

34
export abstract class BaseDuckDBType {
45
public readonly typeId: DuckDBTypeId;
56
protected constructor(typeId: DuckDBTypeId) {
67
this.typeId = typeId;
78
}
9+
public toString(): string {
10+
return DuckDBTypeId[this.typeId];
11+
}
812
}
913

1014
export class DuckDBBooleanType extends BaseDuckDBType {
@@ -150,6 +154,9 @@ export class DuckDBDecimalType extends BaseDuckDBType {
150154
this.width = width;
151155
this.scale = scale;
152156
}
157+
public toString(): string {
158+
return `DECIMAL(${this.width},${this.scale})`;
159+
}
153160
public static readonly default = new DuckDBDecimalType(18, 3);
154161
}
155162

@@ -182,6 +189,9 @@ export class DuckDBEnumType extends BaseDuckDBType {
182189
this.values = values;
183190
this.internalTypeId = internalTypeId;
184191
}
192+
public toString(): string {
193+
return `ENUM(${this.values.map(quotedString).join(', ')})`;
194+
}
185195
}
186196

187197
export class DuckDBListType extends BaseDuckDBType {
@@ -190,6 +200,9 @@ export class DuckDBListType extends BaseDuckDBType {
190200
super(DuckDBTypeId.LIST);
191201
this.valueType = valueType;
192202
}
203+
public toString(): string {
204+
return `${this.valueType}[]`;
205+
}
193206
}
194207

195208
export interface DuckDBStructEntryType {
@@ -203,6 +216,11 @@ export class DuckDBStructType extends BaseDuckDBType {
203216
super(DuckDBTypeId.STRUCT);
204217
this.entries = entries;
205218
}
219+
public toString(): string {
220+
return `STRUCT(${this.entries.map(
221+
entry => `${quotedIdentifier(entry.name)} ${entry.valueType}`
222+
).join(', ')})`;
223+
}
206224
}
207225

208226
export class DuckDBMapType extends BaseDuckDBType {
@@ -213,6 +231,9 @@ export class DuckDBMapType extends BaseDuckDBType {
213231
this.keyType = keyType;
214232
this.valueType = valueType;
215233
}
234+
public toString(): string {
235+
return `MAP(${this.keyType}, ${this.valueType})`;
236+
}
216237
}
217238

218239
export class DuckDBArrayType extends BaseDuckDBType {
@@ -223,6 +244,9 @@ export class DuckDBArrayType extends BaseDuckDBType {
223244
this.valueType = valueType;
224245
this.length = length;
225246
}
247+
public toString(): string {
248+
return `${this.valueType}[${this.length}]`;
249+
}
226250
}
227251

228252
export class DuckDBUUIDType extends BaseDuckDBType {
@@ -243,6 +267,11 @@ export class DuckDBUnionType extends BaseDuckDBType {
243267
super(DuckDBTypeId.UNION);
244268
this.alternatives = alternatives;
245269
}
270+
public toString(): string {
271+
return `UNION(${this.alternatives.map(
272+
entry => `${quotedIdentifier(entry.tag)} ${entry.valueType}`
273+
).join(', ')})`;
274+
}
246275
}
247276

248277
export class DuckDBBitType extends BaseDuckDBType {
@@ -256,13 +285,19 @@ export class DuckDBTimeTZType extends BaseDuckDBType {
256285
private constructor() {
257286
super(DuckDBTypeId.TIME_TZ);
258287
}
288+
public toString(): string {
289+
return "TIME WITH TIME ZONE";
290+
}
259291
public static readonly instance = new DuckDBTimeTZType();
260292
}
261293

262294
export class DuckDBTimestampTZType extends BaseDuckDBType {
263295
private constructor() {
264296
super(DuckDBTypeId.TIMESTAMP_TZ);
265297
}
298+
public toString(): string {
299+
return "TIMESTAMP WITH TIME ZONE";
300+
}
266301
public static readonly instance = new DuckDBTimestampTZType();
267302
}
268303

api/src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,4 +13,5 @@ export * from './DuckDBTypeId';
1313
export * from './DuckDBValue';
1414
export * from './DuckDBVector';
1515
export * from './enums';
16+
export * from './sql';
1617
export * from './version';

api/src/sql.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
export function quotedString(input: string): string {
2+
return `'${input.replace(`'`, `''`)}'`;
3+
}
4+
5+
export function quotedIdentifier(input: string): string {
6+
return `"${input.replace(`"`, `""`)}"`;
7+
}

api/test/api.test.ts

Lines changed: 55 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { assert, describe, test } from 'vitest';
22
import {
3+
DuckDBAnyType,
34
DuckDBArrayType,
45
DuckDBArrayVector,
56
DuckDBBigIntType,
@@ -44,6 +45,7 @@ import {
4445
DuckDBMapVector,
4546
DuckDBPendingResultState,
4647
DuckDBResult,
48+
DuckDBSQLNullType,
4749
DuckDBSmallDecimal,
4850
DuckDBSmallIntType,
4951
DuckDBSmallIntVector,
@@ -283,6 +285,10 @@ describe('api', () => {
283285
const ver = version();
284286
assert.ok(ver.startsWith('v'), `version starts with 'v'`);
285287
});
288+
test('should expose configuration option descriptions', () => {
289+
const descriptions = configurationOptionDescriptions();
290+
assert.ok(descriptions['memory_limit'], `descriptions has 'memory_limit'`);
291+
});
286292
test('ReturnResultType enum', () => {
287293
assert.equal(ResultReturnType.INVALID, 0);
288294
assert.equal(ResultReturnType.CHANGED_ROWS, 1);
@@ -353,9 +359,55 @@ describe('api', () => {
353359
assert.equal(StatementType[StatementType.DETACH], 'DETACH');
354360
assert.equal(StatementType[StatementType.MULTI], 'MULTI');
355361
});
356-
test('should expose configuration option descriptions', () => {
357-
const descriptions = configurationOptionDescriptions();
358-
assert.ok(descriptions['memory_limit'], `descriptions has 'memory_limit'`);
362+
test('DuckDBType toString', () => {
363+
assert.equal(DuckDBBooleanType.instance.toString(), 'BOOLEAN');
364+
assert.equal(DuckDBTinyIntType.instance.toString(), 'TINYINT');
365+
assert.equal(DuckDBSmallIntType.instance.toString(), 'SMALLINT');
366+
assert.equal(DuckDBIntegerType.instance.toString(), 'INTEGER');
367+
assert.equal(DuckDBBigIntType.instance.toString(), 'BIGINT');
368+
assert.equal(DuckDBUTinyIntType.instance.toString(), 'UTINYINT');
369+
assert.equal(DuckDBUSmallIntType.instance.toString(), 'USMALLINT');
370+
assert.equal(DuckDBUIntegerType.instance.toString(), 'UINTEGER');
371+
assert.equal(DuckDBUBigIntType.instance.toString(), 'UBIGINT');
372+
assert.equal(DuckDBFloatType.instance.toString(), 'FLOAT');
373+
assert.equal(DuckDBDoubleType.instance.toString(), 'DOUBLE');
374+
assert.equal(DuckDBTimestampType.instance.toString(), 'TIMESTAMP');
375+
assert.equal(DuckDBDateType.instance.toString(), 'DATE');
376+
assert.equal(DuckDBTimeType.instance.toString(), 'TIME');
377+
assert.equal(DuckDBIntervalType.instance.toString(), 'INTERVAL');
378+
assert.equal(DuckDBHugeIntType.instance.toString(), 'HUGEINT');
379+
assert.equal(DuckDBUHugeIntType.instance.toString(), 'UHUGEINT');
380+
assert.equal(DuckDBVarCharType.instance.toString(), 'VARCHAR');
381+
assert.equal(DuckDBBlobType.instance.toString(), 'BLOB');
382+
assert.equal((new DuckDBDecimalType(17, 5)).toString(), 'DECIMAL(17,5)');
383+
assert.equal(DuckDBTimestampSecondsType.instance.toString(), 'TIMESTAMP_S');
384+
assert.equal(DuckDBTimestampMillisecondsType.instance.toString(), 'TIMESTAMP_MS');
385+
assert.equal(DuckDBTimestampNanosecondsType.instance.toString(), 'TIMESTAMP_NS');
386+
assert.equal(
387+
(new DuckDBEnumType(['fly', 'swim', 'walk'], DuckDBTypeId.UTINYINT)).toString(),
388+
`ENUM('fly', 'swim', 'walk')`
389+
);
390+
assert.equal((new DuckDBListType(DuckDBIntegerType.instance)).toString(), 'INTEGER[]');
391+
assert.equal((new DuckDBStructType([
392+
{ name: 'id', valueType: DuckDBVarCharType.instance },
393+
{ name: 'ts', valueType: DuckDBTimestampType.instance },
394+
])).toString(), 'STRUCT("id" VARCHAR, "ts" TIMESTAMP)');
395+
assert.equal(
396+
(new DuckDBMapType(DuckDBIntegerType.instance, DuckDBVarCharType.instance)).toString(),
397+
'MAP(INTEGER, VARCHAR)'
398+
);
399+
assert.equal((new DuckDBArrayType(DuckDBIntegerType.instance, 3)).toString(), 'INTEGER[3]');
400+
assert.equal(DuckDBUUIDType.instance.toString(), 'UUID');
401+
assert.equal((new DuckDBUnionType([
402+
{ tag: 'str', valueType: DuckDBVarCharType.instance },
403+
{ tag: 'num', valueType: DuckDBIntegerType.instance },
404+
])).toString(), 'UNION("str" VARCHAR, "num" INTEGER)');
405+
assert.equal(DuckDBBitType.instance.toString(), 'BIT');
406+
assert.equal(DuckDBTimeTZType.instance.toString(), 'TIME WITH TIME ZONE');
407+
assert.equal(DuckDBTimestampTZType.instance.toString(), 'TIMESTAMP WITH TIME ZONE');
408+
assert.equal(DuckDBAnyType.instance.toString(), 'ANY');
409+
assert.equal(DuckDBVarIntType.instance.toString(), 'VARINT');
410+
assert.equal(DuckDBSQLNullType.instance.toString(), 'SQLNULL');
359411
});
360412
test('should support creating, connecting, running a basic query, and reading results', async () => {
361413
const instance = await DuckDBInstance.create();

0 commit comments

Comments
 (0)