Code Monkey home page Code Monkey logo

cbschuld / rds-data Goto Github PK

View Code? Open in Web Editor NEW
19.0 19.0 6.0 539 KB

A decorator for the AWS Data API for Aurora Serverless. It decorates and abstracts the Amazon SDK's implementation to make it feel more like a traditional MySQL wrapper than an HTTP based web service. It is written in Typescript and provides type-aware return objects which allows for better support in Typescript-based solutions.

License: MIT License

TypeScript 99.43% Shell 0.57%
aurora lambda rds rds-data-service serverless sql

rds-data's People

Contributors

cbschuld avatar dependabot[bot] avatar markherhold avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar

rds-data's Issues

UUID

I got the following error:

{
    "errorType": "Error",
    "errorMessage": "Missing type: uuid",
    "stack": [
        "Error: Missing type: uuid",
        "    at /var/task/node_modules/rds-data/lib/RDSData.js:207:35",
        "    at Array.forEach (<anonymous>)",
        "    at Function.RDSData.resultFormat (/var/task/node_modules/rds-data/lib/RDSData.js:172:30)",
        "    at /var/task/node_modules/rds-data/lib/RDSData.js:96:50",
        "    at processTicksAndRejections (internal/process/task_queues.js:93:5)"
    ]
}

but was able to get around it by casting the UUID field to varchar: id::VARCHAR(36).

Furthermore, I also got the error: "errorMessage": "Missing type: text" and see that the code in the NPM package doesn't uppercase typeName.

Is this package active?

Question: Highload RDS Data API

I am wondering if this library should provide support for highload interaction with RDS Data API?

RDS-serverless is great AWS service, but it has a tons caveats within highload interoperation. For example, DML query result can be received as error, although it had been successfully fulfilled, or transaction commit can be reported as successful, although it had been rollbacked.

There are minimum four known highload RDS Data API issues: https://redd.it/i3gnpz/ , https://redd.it/g0h4jq/ , https://redd.it/i4qcz1 , https://redd.it/f6ag4c/

Some of that issues can be wrapped around in library code by introducing auto-retries on AWS temporary errors and performing additional queries on ambiguous results, which had been caused by RDS-service errors.

At least following RDS services wrappers are mandatory: https://git.io/JUS3K and https://git.io/JUS36 , including inspecting error message name, type, code, message and stack, depend on current error.

Column Types

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 ?

Nullable Types

I am running into an issue that makes it hard to use nullable types. For instance, a table could have an auto-generated ID (UUID or sequential number) and I'd try to match that with a nullable property on an interface: id?: string.

TS error:

Property 'id' of type 'string | undefined' is not assignable to string index type 'RDSDataParameterValue'.

Code:

import { RDSDataParameters } from 'rds-data/lib/RDSData';

export interface Message extends RDSDataParameters {
    id?: string; // error here
    message: string;
}

const m: Message = { message: "hi" };

const { data } = await db.query(
  `INSERT INTO messages(message)
  VALUES(:message)
  RETURNING *`,
  m,
);

What is the recommended approach here?

Decimal Data Type Not Supported

when running the query function, I'm presented with "Missing type: DECIMAL". I tracked it down to that type missing in the case statement inside of resultFormat.

Seems like we could add the type to the case statement, but wanted to ask a question.

Should there be a way for users to opt out of the formatting? To me, that seems like unnecessary logic and could be opt in.

Local Testing

Hey @cbschuld ,

I'm giving this a try and found that I need to be able to pass options (see constructor, types) to the underlying RDSDataService API for local testing.

For example, here's my ideal config:

const isCI = process.env['CI'] === 'true';

export const db = new RDSDatabase({
    region: 'us-east-1',
    secretArn: process.env['SECRET_ARN']!,
    resourceArn: process.env['CLUSTER_ARN']!,
    database: process.env['DB_NAME']!,
    options: isCI
        ? {
              // we're in a test environment
              endpoint: new AWS.Endpoint('http://127.0.0.1:8080'),
              httpOptions: {
                  agent: new http.Agent(),
              },
          }
        : {
              // not in a test environment
          },
});

I'm using koxudaxi/local-data-api for local testing.

Any thoughts on this? Do you do local testing (local stack or a stack in CI), but with a different approach?

eslint not working

Looks like eslint doesn't work. Also, it seems to have some react/jsx/tsx/browser rules.

npm run eslint
=============

WARNING: You are currently running a version of TypeScript which is not officially supported by @typescript-eslint/typescript-estree.

You may find that it works just fine, or you may not.

SUPPORTED TYPESCRIPT VERSIONS: >=3.3.1 <3.8.0

YOUR TYPESCRIPT VERSION: 3.9.3

Please only submit bug reports when using the officially supported version.

=============
Warning: React version was set to "detect" in eslint-plugin-react settings, but the "react" package is not installed. Assuming latest React version for linting.

Oops! Something went wrong! :(

ESLint: 7.0.0

TypeError: Cannot read property 'body' of null
Occurred while linting /Users/Mark/projects/rds-data/lib/RDSData.d.ts:49
    at checkForConstructor (/Users/Mark/projects/rds-data/node_modules/eslint/lib/rules/no-useless-constructor.js:165:42)
    at /Users/Mark/projects/rds-data/node_modules/eslint/lib/linter/safe-emitter.js:45:58
    at Array.forEach (<anonymous>)
    at Object.emit (/Users/Mark/projects/rds-data/node_modules/eslint/lib/linter/safe-emitter.js:45:38)
    at NodeEventGenerator.applySelector (/Users/Mark/projects/rds-data/node_modules/eslint/lib/linter/node-event-generator.js:254:26)
    at NodeEventGenerator.applySelectors (/Users/Mark/projects/rds-data/node_modules/eslint/lib/linter/node-event-generator.js:283:22)
    at NodeEventGenerator.enterNode (/Users/Mark/projects/rds-data/node_modules/eslint/lib/linter/node-event-generator.js:297:14)
    at CodePathAnalyzer.enterNode (/Users/Mark/projects/rds-data/node_modules/eslint/lib/linter/code-path-analysis/code-path-analyzer.js:635:23)
    at /Users/Mark/projects/rds-data/node_modules/eslint/lib/linter/linter.js:948:32
    at Array.forEach (<anonymous>)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.