Skip to content

Column TypesΒ #7

@MarkHerhold

Description

@MarkHerhold

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:

rds-data/src/RDSData.ts

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 undefined when true value is null (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 ?

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions