-
Notifications
You must be signed in to change notification settings - Fork 4
Description
I've been hitting a lot of Missing type: X column errors (where X is uuid, int4, text, and custom enum). It looks like I could just add each DB type until I realized we would need to account for custom enumerations in PostgreSQL and provide those or a parser callback to rds-data. Also, there are an insane number of DB types that we would have to try to assume how to handle, which is never good.
I think that defining each column type for multiple DBs is probably just a loosing battle. Switch statement in question:
Lines 184 to 213 in 49d6f2f
| switch (columns[c].type) { | |
| case 'BINARY': | |
| v.buffer = isNull ? undefined : Buffer.from((record[c].blobValue || '').toString()); | |
| v.string = isNull ? undefined : v.buffer?.toString('base64'); | |
| break; | |
| case 'BIT': | |
| v.boolean = isNull ? undefined : record[c].booleanValue; | |
| v.number = v.boolean ? 1 : 0; | |
| break; | |
| case 'TIMESTAMP': | |
| case 'DATETIME': | |
| case 'DATE': | |
| v.date = isNull ? undefined : new Date(record[c].stringValue ?? ''); | |
| v.string = isNull ? undefined : record[c].stringValue; | |
| v.number = v.date ? v.date.getTime() : 0; | |
| break; | |
| case 'INT': | |
| case 'INT UNSIGNED': | |
| case 'BIGINT': | |
| case 'BIGINT UNSIGNED': | |
| v.number = isNull ? undefined : record[c].longValue; | |
| break; | |
| case 'TEXT': | |
| case 'CHAR': | |
| case 'VARCHAR': | |
| v.string = isNull ? undefined : record[c].stringValue; | |
| break; | |
| default: | |
| throw new Error(`Missing type: ${columns[c].type}`); | |
| } |
As an alternative, we could just return the anticipated value and not rely on column.typeName. Developers will know what type their data should be.
class ColumnValue {
public field: Field; // dev can always pull original Field object
constructor(field: Field) {
this.field = field;
}
get isNull(): boolean {
return !!this.field.isNull;
}
get date(): Date | null {
if (this.isNull) return null;
return new Date(this.field.stringValue!);
}
get string(): string | null {
if (this.isNull) return null;
return this.field.stringValue;
}
get number(): number | null {
if (this.isNull) return null;
return this.field.longValue;
}
// same idea for buffer, boolean, etc
}Pros:
- getters reduce unnecessary computation
- great future compatibility for unanticipated types, custom DB enums/types, no more "error by default"
- less boilerplate
- library doesn't try to be smarter than the developer
- library doesn't assume that binary represented as a string should be Base64
- library doesn't return
undefinedwhen true value isnull(I believe that's what is currently happening)
Cons:
- slight complexity increase with class
- slight interface change (technically breaking)
- proposed solution is still not as clean as a hydrator function
What do you think @cbschuld ?