1
0
mirror of https://github.com/Unleash/unleash.git synced 2025-10-27 11:02:16 +01:00

chore: return user id alongside max updated_at (#10732)

This is for internal use
This commit is contained in:
Gastón Fournier 2025-10-06 11:43:40 +02:00 committed by GitHub
parent c39b4cd1b0
commit b1f4ebd5eb
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 54 additions and 23 deletions

View File

@ -62,4 +62,21 @@ test('returns the users in pages', async () => {
);
expect(usersPage3).toHaveLength(2);
expect(usersPage3[1].username).toBe('test-user-9');
const usersPage4 = await userUpdatesReadModel.getUsersUpdatedAfterOrEqual(
INSERT_INSTANT,
pageSize,
usersPage3[usersPage3.length - 1].id,
);
expect(usersPage4).toHaveLength(0);
});
test('getLastUpdatedAt returns the latest updated_at timestamp with max id', async () => {
const userUpdatesReadModel = db.stores.userUpdatesReadModel;
const result = await userUpdatesReadModel.getLastUpdatedAt();
expect(result).not.toBeNull();
expect(result?.lastUpdatedAt).toEqual(INSERT_INSTANT);
expect(result?.userId).toBeDefined();
expect(result?.userId).toBe(10); // The last inserted user should have the highest ID
});

View File

@ -38,16 +38,26 @@ export class UserUpdatesReadModel {
this.logger = getLogger('user-updates-read-model.ts');
}
async getLastUpdatedAt(): Promise<Date | null> {
async getLastUpdatedAt(): Promise<{
lastUpdatedAt: Date;
userId: number;
} | null> {
const result = await this.db(USERS_TABLE)
.select('id', 'updated_at')
.where({
// also consider deleted users (different than activeUsers query)
is_system: false,
is_service: false,
})
.max('updated_at as last_updated_at')
.orderBy('updated_at', 'desc')
.orderBy('id', 'desc')
.first();
return result ? result.last_updated_at : null;
return result
? {
lastUpdatedAt: result.updated_at,
userId: result.id,
}
: null;
}
/** @deprecated */

View File

@ -15,10 +15,10 @@ beforeEach(async () => {
test('should have no users', async () => {
const readModel = stores.userUpdatesReadModel;
const lastUpdatedAt = await readModel.getLastUpdatedAt();
expect(lastUpdatedAt).toBeNull();
const lastUpdate = await readModel.getLastUpdatedAt();
expect(lastUpdate).toBeNull();
const users = await readModel.getUsersUpdatedAfter(new Date(0));
const users = await readModel.getUsersUpdatedAfterOrEqual(new Date(0));
expect(users).toEqual([]);
});
@ -28,15 +28,15 @@ test('Adding a user should return that user', async () => {
const beforeInsert = new Date(Date.now() - 1000);
await userStore.upsert({ email: 'test@example.com' });
const lastUpdatedAt = await readModel.getLastUpdatedAt();
expect(lastUpdatedAt).toBeDefined();
expect(lastUpdatedAt).toBeInstanceOf(Date);
const lastUpdate = await readModel.getLastUpdatedAt();
expect(lastUpdate).toBeDefined();
expect(lastUpdate!.lastUpdatedAt).toBeInstanceOf(Date);
// check that it's recent
expect(lastUpdatedAt!.getTime()).toBeGreaterThanOrEqual(
expect(lastUpdate!.lastUpdatedAt!.getTime()).toBeGreaterThanOrEqual(
beforeInsert.getTime(),
);
const users = await readModel.getUsersUpdatedAfter(beforeInsert);
const users = await readModel.getUsersUpdatedAfterOrEqual(beforeInsert);
expect(users).toHaveLength(1);
expect(users[0].email).toBe('test@example.com');
expect(users[0].createdAt).toBeInstanceOf(Date);
@ -52,23 +52,25 @@ test('Modifying a user should return that user', async () => {
});
const afterInsert = new Date();
const lastUpdatedAt = await readModel.getLastUpdatedAt();
expect(lastUpdatedAt).toBeDefined();
const lastUpdate = await readModel.getLastUpdatedAt();
expect(lastUpdate).toBeDefined();
const lastUpdatedAt = lastUpdate!.lastUpdatedAt;
expect(lastUpdatedAt).toBeInstanceOf(Date);
const users = await readModel.getUsersUpdatedAfter(afterInsert);
const users = await readModel.getUsersUpdatedAfterOrEqual(afterInsert);
expect(users).toHaveLength(0);
await userStore.update(inserted.id, { name: 'New Name' });
const lastUpdatedAt2 = await readModel.getLastUpdatedAt();
expect(lastUpdatedAt2).toBeDefined();
const lastUpdate2 = await readModel.getLastUpdatedAt();
expect(lastUpdate2).toBeDefined();
const lastUpdatedAt2 = lastUpdate2!.lastUpdatedAt;
expect(lastUpdatedAt2).toBeInstanceOf(Date);
expect(lastUpdatedAt2!.getTime()).toBeGreaterThanOrEqual(
lastUpdatedAt!.getTime(),
);
const users2 = await readModel.getUsersUpdatedAfter(afterInsert);
const users2 = await readModel.getUsersUpdatedAfterOrEqual(afterInsert);
expect(users2).toHaveLength(1);
expect(users2[0].email).toBe('test@example.com');
expect(users2[0].name).toBe('New Name');
@ -85,23 +87,25 @@ test('Deleting a user should return that user', async () => {
});
const afterInsert = new Date();
const lastUpdatedAt = await readModel.getLastUpdatedAt();
expect(lastUpdatedAt).toBeDefined();
const lastUpdate = await readModel.getLastUpdatedAt();
expect(lastUpdate).toBeDefined();
const lastUpdatedAt = lastUpdate!.lastUpdatedAt;
expect(lastUpdatedAt).toBeInstanceOf(Date);
const users = await readModel.getUsersUpdatedAfter(afterInsert);
const users = await readModel.getUsersUpdatedAfterOrEqual(afterInsert);
expect(users).toHaveLength(0);
await userStore.delete(inserted.id);
const lastUpdatedAt2 = await readModel.getLastUpdatedAt();
expect(lastUpdatedAt2).toBeDefined();
const lastUpdate2 = await readModel.getLastUpdatedAt();
expect(lastUpdate2).toBeDefined();
const lastUpdatedAt2 = lastUpdate2!.lastUpdatedAt;
expect(lastUpdatedAt2).toBeInstanceOf(Date);
expect(lastUpdatedAt2!.getTime()).toBeGreaterThanOrEqual(
lastUpdatedAt!.getTime(),
);
const users2 = await readModel.getUsersUpdatedAfter(afterInsert);
const users2 = await readModel.getUsersUpdatedAfterOrEqual(afterInsert);
expect(users2).toHaveLength(1);
expect(users2[0].email).toBeNull(); // currently we nullify the email but this might change in the future
expect(users2[0].createdAt).toBeInstanceOf(Date);