Skip to content

Column Types #7

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 ?

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

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