typeorm-aurora-data-api-driver
typeorm-aurora-data-api-driver copied to clipboard
Cannot save null values: Cannot convert undefined or null to object
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
- 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)
}
})
}
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!
@ArnaudDutant Looks to be the same error to me.
Should be fixed in 2.1.1, please let me know if you have more issues with it.
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?
I think we need to check where undefined is handled when using the "normal" MySQL/Postgres drivers and try to replicate similar behavior.
For me with version 2.2.0 passing a null
value does work (param 3):
So I'm not sure what the issue could be for you @seawatts.
I also faced this issue. At least it would be nice to have some proper error description, like what field goes wrong etc...
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 https://github.com/ArsenyYankovsky/typeorm-aurora-data-api-driver/blob/c01d226382ff700f7986f75ae3078ef6aa7ce92a/src/query-transformer/mysql-query-transformer.ts#L154
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