Update edit history service tests and implementation
This commit is contained in:
parent
60d087c424
commit
297f7ccf5f
@ -1,5 +1,5 @@
|
||||
import { EditHistoryEntry } from '../../../frontend/models/edit-history-entry';
|
||||
import { numDesc } from '../../../helpers';
|
||||
import { numAsc, numDesc } from '../../../helpers';
|
||||
|
||||
const mockEditHistory =
|
||||
jest.genMockFromModule('../editHistory') as typeof import('../editHistory') & {
|
||||
@ -16,22 +16,16 @@ mockEditHistory.getHistoryAfterId = function(id: string, count: number): Promise
|
||||
return Promise.resolve(
|
||||
mockData
|
||||
.filter(x => BigInt(x.revision_id) > BigInt(id))
|
||||
.sort(numAsc(x => BigInt(x.revision_id)))
|
||||
.slice(0, count)
|
||||
.sort(numDesc(x => BigInt(x.revision_id)))
|
||||
);
|
||||
};
|
||||
|
||||
mockEditHistory.getHistoryBeforeId = function(id: string, count: number): Promise<EditHistoryEntry[]> {
|
||||
let filteredData = id == undefined ? mockData : mockData.filter(x => BigInt(x.revision_id) < BigInt(id));
|
||||
return Promise.resolve(
|
||||
mockData
|
||||
.filter(x => BigInt(x.revision_id) < BigInt(id))
|
||||
.slice(0, count)
|
||||
);
|
||||
};
|
||||
|
||||
mockEditHistory.getLatestHistory = function(count: number): Promise<EditHistoryEntry[]> {
|
||||
|
||||
return Promise.resolve(
|
||||
mockData
|
||||
filteredData
|
||||
.slice(0, count)
|
||||
);
|
||||
};
|
||||
|
@ -31,20 +31,23 @@ export function getHistoryAfterId(id: string, count: number): Promise<EditHistor
|
||||
}
|
||||
|
||||
export function getHistoryBeforeId(id: string, count: number): Promise<EditHistoryEntry[]> {
|
||||
return db.manyOrNone(`
|
||||
${baseQuery}
|
||||
WHERE log_id < $1
|
||||
ORDER BY revision_id DESC
|
||||
LIMIT $2
|
||||
`, [id, count]);
|
||||
}
|
||||
|
||||
export async function getLatestHistory(count: number) : Promise<EditHistoryEntry[]> {
|
||||
return await db.manyOrNone(`
|
||||
${baseQuery}
|
||||
ORDER BY revision_id DESC
|
||||
LIMIT $1
|
||||
`, [count]);
|
||||
if(id == undefined) {
|
||||
|
||||
return db.any(`
|
||||
${baseQuery}
|
||||
ORDER BY revision_id DESC
|
||||
LIMIT $1
|
||||
`, [count]);
|
||||
|
||||
} else {
|
||||
|
||||
return db.any(`
|
||||
${baseQuery}
|
||||
WHERE log_id < $1
|
||||
ORDER BY revision_id DESC
|
||||
LIMIT $2
|
||||
`, [id, count]);
|
||||
}
|
||||
}
|
||||
|
||||
export async function getIdOlderThan(id: string): Promise<string> {
|
||||
|
@ -1,5 +1,3 @@
|
||||
import { mocked } from 'ts-jest/utils';
|
||||
|
||||
import { EditHistoryEntry } from '../../../frontend/models/edit-history-entry';
|
||||
import * as editHistoryData from '../../dataAccess/editHistory'; // manually mocked
|
||||
import { getGlobalEditHistory } from '../editHistory';
|
||||
@ -8,36 +6,115 @@ jest.mock('../../dataAccess/editHistory');
|
||||
|
||||
const mockedEditHistoryData = editHistoryData as typeof import('../../dataAccess/__mocks__/editHistory');
|
||||
|
||||
describe('getGlobalEditHistory()', () => {
|
||||
mockedEditHistoryData.__setHistory(
|
||||
[...Array(20).keys()].map<EditHistoryEntry>(i => ({
|
||||
revision_id: (100 + i) + '',
|
||||
revision_timestamp: new Date(2019, 10, 1, 17, 20 + i).toISOString(),
|
||||
username: 'testuser',
|
||||
building_id: 1234567,
|
||||
forward_patch: {},
|
||||
reverse_patch: {}
|
||||
}))
|
||||
);
|
||||
function generateHistory(n: number, firstId: number = 100) {
|
||||
return [...Array(n).keys()].map<EditHistoryEntry>(i => ({
|
||||
revision_id: (firstId + i) + '',
|
||||
revision_timestamp: new Date(2019, 10, 1, 17, 20 + i).toISOString(),
|
||||
username: 'testuser',
|
||||
building_id: 1234567,
|
||||
forward_patch: {},
|
||||
reverse_patch: {}
|
||||
}));
|
||||
}
|
||||
|
||||
describe('getGlobalEditHistory()', () => {
|
||||
|
||||
beforeEach(() => {
|
||||
mockedEditHistoryData.__setHistory(
|
||||
generateHistory(20)
|
||||
);
|
||||
});
|
||||
|
||||
describe('getting history before a point', () => {
|
||||
|
||||
it('should return latest history if no ID specified', async () => {
|
||||
const result = await getGlobalEditHistory(null, null, 5);
|
||||
|
||||
expect(result.history.map(x => x.revision_id)).toEqual(['119', '118', '117', '116', '115']);
|
||||
});
|
||||
|
||||
describe('without before/after parameters', () => {
|
||||
it.each(
|
||||
[
|
||||
[0, []],
|
||||
[3, ['119', '118', '117']],
|
||||
[6, ['119', '118', '117', '116', '115', '114']]
|
||||
[null, 3, ['119', '118', '117']],
|
||||
[null, 6, ['119', '118', '117', '116', '115', '114']],
|
||||
['118', 0, []],
|
||||
]
|
||||
)('should return the N latest records in descending order', async (count: number, ids: string[]) => {
|
||||
const historyResult = await getGlobalEditHistory(null, null, count);
|
||||
)('should return the N records before the specified ID in descending order [beforeId: %p, count: %p]', async (
|
||||
beforeId: string, count: number, ids: string[]
|
||||
) => {
|
||||
const result = await getGlobalEditHistory(beforeId, null, count);
|
||||
|
||||
expect(historyResult.history.map(h => h.revision_id)).toEqual(ids);
|
||||
expect(result.history.map(h => h.revision_id)).toEqual(ids);
|
||||
});
|
||||
|
||||
it.each([
|
||||
[null, 4, true, false],
|
||||
[null, 10, true, false],
|
||||
[null, 20, false, false],
|
||||
[null, 30, false, false],
|
||||
['50', 10, false, true],
|
||||
['100', 10, false, true],
|
||||
['105', 2, true, true],
|
||||
])('should indicate if there are any newer or older records [beforeId: %p, count: %p]', async (
|
||||
beforeId: string, count: number, hasOlder: boolean, hasNewer: boolean
|
||||
) => {
|
||||
const result = await getGlobalEditHistory(beforeId, null, count);
|
||||
|
||||
expect(result.paging.has_older).toBe(hasOlder);
|
||||
expect(result.paging.has_newer).toBe(hasNewer);
|
||||
});
|
||||
|
||||
|
||||
it('should not return more than 100 entries', async () => {
|
||||
mockedEditHistoryData.__setHistory(
|
||||
generateHistory(200)
|
||||
);
|
||||
|
||||
const result = await getGlobalEditHistory(null, null, 200);
|
||||
|
||||
expect(result.paging.has_older).toBeTruthy();
|
||||
expect(result.history.length).toBe(100);
|
||||
});
|
||||
|
||||
it('should default to 100 entries', async () => {
|
||||
mockedEditHistoryData.__setHistory(
|
||||
generateHistory(200)
|
||||
);
|
||||
|
||||
const result = await getGlobalEditHistory(null, null, 200);
|
||||
|
||||
expect(result.paging.has_older).toBeTruthy();
|
||||
expect(result.history.length).toBe(100);
|
||||
});
|
||||
});
|
||||
|
||||
describe('with after ID parameter', () => {
|
||||
});
|
||||
|
||||
describe('with before ID parameter', () => {
|
||||
describe('getting history after a point', () => {
|
||||
|
||||
it.each([
|
||||
['100', 7, ['107', '106', '105', '104', '103', '102', '101']],
|
||||
['115', 3, ['118', '117', '116']],
|
||||
['120', 10, []]
|
||||
])('should return N records after requested ID in descending order [afterId: %p, count: %p]', async (
|
||||
afterId: string, count: number, expected: string[]
|
||||
) => {
|
||||
const result = await getGlobalEditHistory(null, afterId, count);
|
||||
|
||||
expect(result.history.map(x => x.revision_id)).toEqual(expected);
|
||||
});
|
||||
|
||||
it.each([
|
||||
['99', 10, false, true],
|
||||
['110', 5, true, true],
|
||||
['119', 20, true, false],
|
||||
['99', 20, false, false]
|
||||
])('should indicate if there are any newer or older records [afterId: %p, count: %p]', async (
|
||||
afterId: string, count: number, hasOlder:boolean, hasNewer: boolean
|
||||
) => {
|
||||
const result = await getGlobalEditHistory(null, afterId, count);
|
||||
|
||||
expect(result.paging.has_older).toBe(hasOlder);
|
||||
expect(result.paging.has_newer).toBe(hasNewer);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -1,25 +1,34 @@
|
||||
import { EditHistoryEntry } from '../../frontend/models/edit-history-entry';
|
||||
import { getHistoryAfterId, getHistoryBeforeId, getIdNewerThan, getIdOlderThan, getLatestHistory } from '../dataAccess/editHistory';
|
||||
import { getHistoryAfterId, getHistoryBeforeId, getIdNewerThan, getIdOlderThan } from '../dataAccess/editHistory';
|
||||
|
||||
async function getGlobalEditHistory(beforeId?: string, afterId?: string, count: number = 100) {
|
||||
if(count > 100) count = 100;
|
||||
|
||||
// limited set of records. Expected to be already ordered from newest to oldest
|
||||
let editHistoryRecords: EditHistoryEntry[];
|
||||
|
||||
if(afterId != undefined) {
|
||||
editHistoryRecords = await getHistoryAfterId(afterId, count);
|
||||
} else if (beforeId != undefined) {
|
||||
editHistoryRecords = await getHistoryBeforeId(beforeId, count);
|
||||
} else {
|
||||
editHistoryRecords = await getLatestHistory(count);
|
||||
editHistoryRecords = await getHistoryBeforeId(beforeId, count);
|
||||
}
|
||||
|
||||
const newer = await getIdNewerThan(editHistoryRecords[0]?.revision_id);
|
||||
const older = await getIdOlderThan(editHistoryRecords[editHistoryRecords.length-1]?.revision_id);
|
||||
const currentBatchNewerBound = editHistoryRecords[0]?.revision_id ?? beforeId;
|
||||
const newer = currentBatchNewerBound && await getIdNewerThan(currentBatchNewerBound);
|
||||
|
||||
const currentBatchOlderBound = editHistoryRecords[editHistoryRecords.length-1]?.revision_id ?? afterId;
|
||||
const older = currentBatchOlderBound && await getIdOlderThan(currentBatchOlderBound);
|
||||
|
||||
const hasNewer = newer != undefined;
|
||||
const hasOlder = older != undefined;
|
||||
|
||||
return {
|
||||
history: editHistoryRecords,
|
||||
paging: {
|
||||
has_newer: newer != undefined,
|
||||
has_older: older != undefined
|
||||
has_newer: hasNewer,
|
||||
id_for_newer_query: null,
|
||||
has_older: hasOlder,
|
||||
id_for_older_query: null
|
||||
}
|
||||
};
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user