-
-
Notifications
You must be signed in to change notification settings - Fork 6.5k
Description
Issue type:
[x] bug report
Database system/driver:
[x] mysql
TypeORM version:
[x] 0.x.x (0.2.24)
Steps to reproduce or a small repository showing the problem:
I am trying to cache users by their username, and everything works fine when eager:false. When true cache is stored with the whole query as Redis key. This bug could provide incorrect result when cache is enabled and eager:true is used. I have managed to reproduce it has below.
User.ts
@Entity()
export class User {
@PrimaryGeneratedColumn()
id: number;
@Column({nullable: true, unique: true})
username?: string;
@OneToOne(
() => Profile,
(profile) => profile.user,
{eager: true}
)
@JoinColumn()
profile: Profile;
}Profile.ts
@Entity()
export class Profile {
@PrimaryGeneratedColumn()
id: number;
@OneToOne(
() => User,
(user) => user.profile
)
user: User;
}UserRepository .ts
@EntityRepository(User)
export class UserRepository extends Repository<User> {
async findByUsername(username: string): Promise<User> {
const user = await this.findOne({
where: {username},
cache: {
id: `username:${username}`,
milliseconds: 24 * 60 * 60 * 1000
}
});
if (!user) {
throw new Error(`user with ${username} was not found!!!`);
}
return user;
}
}UserRepository.test.ts
describe('User Tests', () => {
it('should save cache with identifier when eager:true', async () => {
const userRepository = getCustomRepository(UserRepository);
const username = 'mwanza';
try {
await userRepository.findByUsername(username);
expect(1).toEqual(5); //In case above passed.
} catch (e) {
expect(e.message).toMatch(new RegExp(username));
}
const redisKey = await redis.get(`username:${username}`); //Passing cache key as used above.
expect(redisKey).not.toBeNull(); //Received: null
});
});In above expected cache key/identifier to be username:mwanza instead it stores the whole query as key/identifier. This don't give us granular control of cache using this way
await connection.queryResultCache.remove([`username:mwanza`]);So only way to clear cache is to wait until it expires and as result it leads to incorrect results.
key: SELECT DISTINCT `distinctAlias`.`User_id` as "ids_User_id" FROM (SELECT `User`.`id` AS `User_id`, `User`.`username` AS `User_username`, `User`.`profileId` AS `User_profileId`, `User_profile`.`id` AS `User_profile_id` FROM `user` `User` LEFT JOIN `profile` `User_profile` ON `User_profile`.`id`=`User`.`profileId` WHERE `User`.`username` = ?) `distinctAlias` ORDER BY `User_id` ASC LIMIT 1 -- PARAMETERS: ["mwanza"]
value { "query": "SELECT DISTINCT `distinctAlias`.`User_id` as \"ids_User_id\" FROM (SELECT `User`.`id` AS `User_id`, `User`.`username` AS `User_username`, `User`.`profileId` AS `User_profileId`, `User_profile`.`id` AS `User_profile_id` FROM `user` `User` LEFT JOIN `profile` `User_profile` ON `User_profile`.`id`=`User`.`profileId` WHERE `User`.`username` = ?) `distinctAlias` ORDER BY `User_id` ASC LIMIT 1 -- PARAMETERS: [\"mwanza\"]", "time": 1588347815582, "duration": 86400000, "result": "[]" }
When eager:false everything goes well.

key: username:mwanza
