Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cannot save null values: Cannot convert undefined or null to object #83

Open
clalexander opened this issue May 10, 2021 · 8 comments
Open

Comments

@clalexander
Copy link

clalexander commented May 10, 2021

Issue

Cannot save null values to mysql database. Null query parameter values fail to map correctly in normalizeParams, resulting in TypeError: Cannot convert undefined or null to object

Stack Trace

TypeError: Cannot convert undefined or null to object
    at Function.keys (<anonymous>)
    at app/node_modules/typeorm-aurora-data-api-driver/dist/typeorm-aurora-data-api-driver.umd.js:440
    at Array.reduce (<anonymous>)
    at normalizeParams (app/node_modules/typeorm-aurora-data-api-driver/dist/typeorm-aurora-data-api-driver.umd.js:437)
    at query (app/node_modules/typeorm-aurora-data-api-driver/dist/typeorm-aurora-data-api-driver.umd.js:688)
    at Object.query (app/node_modules/typeorm-aurora-data-api-driver/dist/typeorm-aurora-data-api-driver.umd.js:908)
    at DataApiDriver.<anonymous> (app/node_modules/typeorm-aurora-data-api-driver/dist/typeorm-aurora-data-api-driver.umd.js:1344)
    at step (app/node_modules/typeorm-aurora-data-api-driver/dist/typeorm-aurora-data-api-driver.umd.js:81)
    at Object.next (app/node_modules/typeorm-aurora-data-api-driver/dist/typeorm-aurora-data-api-driver.umd.js:62)
    at app/node_modules/typeorm-aurora-data-api-driver/dist/typeorm-aurora-data-api-driver.umd.js:55
    at new Promise (<anonymous>)
    at __awaiter (app/node_modules/typeorm-aurora-data-api-driver/dist/typeorm-aurora-data-api-driver.umd.js:51)
    at DataApiDriver.query (app/node_modules/typeorm-aurora-data-api-driver/dist/typeorm-aurora-data-api-driver.umd.js:1336)
    at AuroraDataApiQueryRunner.<anonymous> (app/node_modules/typeorm/driver/aurora-data-api/AuroraDataApiQueryRunner.js:174)
    at step (app/node_modules/typeorm/node_modules/tslib/tslib.js:141)
    at Object.next (app/node_modules/typeorm/node_modules/tslib/tslib.js:122)

Steps to Reproduce

  1. Save an entity with a field that has a null value.

Package versions and database engine type:

  • Database Engine: [mysql 5.7]
  • TypeORM Version: [0.2.30]
  • Driver Version [2.1.0]

Additional Context

  • NestJS [^7.0.0]
  • NestJS Typeorm [7.1.5]

Debug Tracing

First, src/query-transformer/mysql-query-transformer.ts:127
transformParameters(parameters?: any[]) maps all null (and undefined) parameters to null, and not to the object of type { name: ``param_${index}``, value: parameter }.

Then in normalizeParams in dist/typeorm-aurora-data-api.umd.js:

const normalizeParams = params => params.reduce((acc, p) =>
  Array.isArray(p) ? acc.concat([normalizeParams(p)])
  : (
    (Object.keys(p).length === 2 && p.name && p.value !== 'undefined') ||
    (Object.keys(p).length === 3 && p.name && p.value !== 'undefined' && p.cast)
  ) ? acc.concat(p)
    : acc.concat(splitParams(p))
, []);

which takes the transformed parameters from above into params. It expects each element to be either an array or an object with two or three keys. When p is null, Object.keys(p) throws the error TypeError: Cannot convert undefined or null to object.

Because the mysql query transformer transformParameters returns null for null parameter values, it breaks in normalizeParams.

Suggested Fix

At src/query-transformer/mysql-query-transformer.ts:127, make the following changes:

protected transformParameters(parameters?: any[]) {
    if (!parameters) {
      return parameters
    }

    const expandedParameters = this.expandArrayParameters(parameters)

    return expandedParameters.map((parameter, index) => {
      if (parameter === undefined) { // << remove parameter === null
        return parameter
      }

      if (typeof parameter === 'object' && parameter !== null && parameter.value) { // << add parameter !== null
        return ({
          name: `param_${index}`,
          ...parameter,
        })
      }

      return {
        name: `param_${index}`,
        value: parameter, // << value here will be null for null parameters (works in my testing)
      }
    })
  }
@Arnaud-DT
Copy link

Arnaud-DT commented May 25, 2021

Hi,
I'm wondering if I've had the same bug or if it's just me doing things wrong (I'm new to typeorm and the aurora data api driver).

I have a one to one relationship between two tables. In a simplified version:

@Entity()
export class UserEntity {
    @PrimaryColumn()
    email: string;

    @OneToOne(() => RefreshTokenEntity, refreshToken => refreshToken.user, {nullable: true})
    @JoinColumn()
    refreshToken: RefreshTokenEntity;
}
@Entity()
export class RefreshTokenEntity {
  @PrimaryColumn()
  hashedSignature: string;

  @OneToOne(() => UserEntity, user => user.refreshToken)
  user: UserEntity
}

I'm trying to delete any row in RefreshTokenEntity linked to a specific user. As per typeorm documentation, I'm using set(null) to do this:

        .createQueryBuilder()
        .relation(UserEntity, "refreshToken")
        .of(user)
        .set(null);

However I get this error (the stack trace looks similar to the one you have @clalexander):

    at Function.keys (<anonymous>)
    at /var/task/node_modules/typeorm-aurora-data-api-driver/dist/typeorm-aurora-data-api-driver.umd.js:440:17
    at Array.reduce (<anonymous>)
    at normalizeParams (/var/task/node_modules/typeorm-aurora-data-api-driver/dist/typeorm-aurora-data-api-driver.umd.js:437:46)
    at query (/var/task/node_modules/typeorm-aurora-data-api-driver/dist/typeorm-aurora-data-api-driver.umd.js:687:26)
    at Object.query (/var/task/node_modules/typeorm-aurora-data-api-driver/dist/typeorm-aurora-data-api-driver.umd.js:907:26)
    at DataApiDriver.<anonymous> (/var/task/node_modules/typeorm-aurora-data-api-driver/dist/typeorm-aurora-data-api-driver.umd.js:1340:62)
    at step (/var/task/node_modules/typeorm-aurora-data-api-driver/dist/typeorm-aurora-data-api-driver.umd.js:81:27)
    at Object.next (/var/task/node_modules/typeorm-aurora-data-api-driver/dist/typeorm-aurora-data-api-driver.umd.js:62:57)
    at /var/task/node_modules/typeorm-aurora-data-api-driver/dist/typeorm-aurora-data-api-driver.umd.js:55:75

Thanks for your insight!

@clalexander
Copy link
Author

@ArnaudDutant Looks to be the same error to me.

@ArsenyYankovsky
Copy link
Owner

Should be fixed in 2.1.1, please let me know if you have more issues with it.

@seawatts
Copy link
Contributor

Still seeing this error when used with Postgres. @ArsenyYankovsky

Looking into it now. My first assumption is that you should be able to pass in undefined as a parameter and the query should basically just drop that param. i.e. do not set it to null. However, it seems like the undefined param is getting passed all the way day to the data API lib and then crashes there.

I'm not sure if the driver should be dealing with this, or if it's upstream in TypeORM. My guess is that it should be getting taken care of upstream. So that by the time we get the query string and parameters it is already omited. I could be wrong though.

Thoughts?

@ArsenyYankovsky
Copy link
Owner

ArsenyYankovsky commented Jun 19, 2021

I think we need to check where undefined is handled when using the "normal" MySQL/Postgres drivers and try to replicate similar behavior.

@harm-less
Copy link

harm-less commented Jul 13, 2021

For me with version 2.2.0 passing a null value does work (param 3):

image

So I'm not sure what the issue could be for you @seawatts.

@qstyler
Copy link

qstyler commented Nov 2, 2021

I also faced this issue. At least it would be nice to have some proper error description, like what field goes wrong etc...

@CorentinDoue
Copy link

I face a similar issue with "typeorm-aurora-data-api-driver": "2.3.4" and mysql.

I can't save empty set.

  @Column({ type: 'set', enum: enumValues(NetworkType)})
  networkType: NetworkType[];

An empty array [] is transformed in empty string '' by typeorm.
The parameter is { value: '' } which fails this condition

if (typeof parameter === 'object' && parameter?.value) {

The resulting parameter is

{
 name: "param_1",
 value: {
   value: '',
 },
}

which breaks later because it is invalid

console.error                                                                                                                                                                                                    
    Error: 'param_1' is an invalid type                                                                                                                                                                            
        at error (node_modules/typeorm-aurora-data-api-driver/node_modules/data-api-client/index.js:39:35)                                                                      
        at formatType (node_modules/typeorm-aurora-data-api-driver/node_modules/data-api-client/index.js:215:4)                                                                 
        at formatParam (node_modules/typeorm-aurora-data-api-driver/dist/typeorm-aurora-data-api-driver.umd.js:481:48)                                                          
        at node_modules/typeorm-aurora-data-api-driver/node_modules/data-api-client/index.js:136:20                        

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

7 participants