You've already forked joplin
mirror of
https://github.com/laurent22/joplin.git
synced 2025-07-16 00:14:34 +02:00
Api: Resolves #5199: Add support for "events" end point to retrieve info about latest note changes
This commit is contained in:
@ -1,13 +1,13 @@
|
||||
const { revisionService, setupDatabaseAndSynchronizer, db, switchClient } = require('../testing/test-utils.js');
|
||||
const SearchEngine = require('../services/searchengine/SearchEngine').default;
|
||||
const ResourceService = require('../services/ResourceService').default;
|
||||
const ItemChangeUtils = require('../services/ItemChangeUtils').default;
|
||||
const Note = require('../models/Note').default;
|
||||
const ItemChange = require('../models/ItemChange').default;
|
||||
import { revisionService, setupDatabaseAndSynchronizer, db, switchClient, msleep } from '../testing/test-utils';
|
||||
import SearchEngine from '../services/searchengine/SearchEngine';
|
||||
import ResourceService from '../services/ResourceService';
|
||||
import ItemChangeUtils from '../services/ItemChangeUtils';
|
||||
import Note from '../models/Note';
|
||||
import ItemChange from '../models/ItemChange';
|
||||
|
||||
let searchEngine = null;
|
||||
let searchEngine: SearchEngine = null;
|
||||
|
||||
describe('models_ItemChange', function() {
|
||||
describe('models/ItemChange', function() {
|
||||
|
||||
beforeEach(async (done) => {
|
||||
await setupDatabaseAndSynchronizer(1);
|
||||
@ -27,17 +27,28 @@ describe('models_ItemChange', function() {
|
||||
const resourceService = new ResourceService();
|
||||
|
||||
await searchEngine.syncTables();
|
||||
|
||||
// If we run this now, it should not delete any change because
|
||||
// the resource service has not yet processed the change
|
||||
await ItemChangeUtils.deleteProcessedChanges();
|
||||
await ItemChangeUtils.deleteProcessedChanges(0);
|
||||
expect(await ItemChange.lastChangeId()).toBe(1);
|
||||
|
||||
await resourceService.indexNoteResources();
|
||||
await ItemChangeUtils.deleteProcessedChanges();
|
||||
await ItemChangeUtils.deleteProcessedChanges(0);
|
||||
expect(await ItemChange.lastChangeId()).toBe(1);
|
||||
|
||||
await revisionService().collectRevisions();
|
||||
|
||||
// If we don't set a TTL it will default to 90 days so it won't delete
|
||||
// either.
|
||||
await ItemChangeUtils.deleteProcessedChanges();
|
||||
expect(await ItemChange.lastChangeId()).toBe(1);
|
||||
|
||||
// All changes should be at least 4 ms old now
|
||||
await msleep(4);
|
||||
|
||||
// Now it should delete all changes older than 3 ms
|
||||
await ItemChangeUtils.deleteProcessedChanges(3);
|
||||
expect(await ItemChange.lastChangeId()).toBe(0);
|
||||
}));
|
||||
|
@ -1,8 +1,14 @@
|
||||
import BaseModel, { ModelType } from '../BaseModel';
|
||||
import shim from '../shim';
|
||||
import eventManager from '../eventManager';
|
||||
import { ItemChangeEntity } from '../services/database/types';
|
||||
const Mutex = require('async-mutex').Mutex;
|
||||
|
||||
export interface ChangeSinceIdOptions {
|
||||
limit?: number;
|
||||
fields?: string[];
|
||||
}
|
||||
|
||||
export default class ItemChange extends BaseModel {
|
||||
|
||||
private static addChangeMutex_: any = new Mutex();
|
||||
@ -24,7 +30,7 @@ export default class ItemChange extends BaseModel {
|
||||
return BaseModel.TYPE_ITEM_CHANGE;
|
||||
}
|
||||
|
||||
static async add(itemType: ModelType, itemId: string, type: number, changeSource: any = null, beforeChangeItemJson: string = null) {
|
||||
public static async add(itemType: ModelType, itemId: string, type: number, changeSource: any = null, beforeChangeItemJson: string = null) {
|
||||
if (changeSource === null) changeSource = ItemChange.SOURCE_UNSPECIFIED;
|
||||
if (!beforeChangeItemJson) beforeChangeItemJson = '';
|
||||
|
||||
@ -57,14 +63,14 @@ export default class ItemChange extends BaseModel {
|
||||
}
|
||||
}
|
||||
|
||||
static async lastChangeId() {
|
||||
public static async lastChangeId() {
|
||||
const row = await this.db().selectOne('SELECT max(id) as max_id FROM item_changes');
|
||||
return row && row.max_id ? row.max_id : 0;
|
||||
}
|
||||
|
||||
// Because item changes are recorded in the background, this function
|
||||
// can be used for synchronous code, in particular when unit testing.
|
||||
static async waitForAllSaved() {
|
||||
public static async waitForAllSaved() {
|
||||
return new Promise((resolve) => {
|
||||
const iid = shim.setInterval(() => {
|
||||
if (!ItemChange.saveCalls_.length) {
|
||||
@ -75,8 +81,32 @@ export default class ItemChange extends BaseModel {
|
||||
});
|
||||
}
|
||||
|
||||
static async deleteOldChanges(lowestChangeId: number) {
|
||||
public static async deleteOldChanges(lowestChangeId: number, itemMinTtl: number) {
|
||||
if (!lowestChangeId) return;
|
||||
return this.db().exec('DELETE FROM item_changes WHERE id <= ?', [lowestChangeId]);
|
||||
|
||||
const cutOffDate = Date.now() - itemMinTtl;
|
||||
|
||||
return this.db().exec(`
|
||||
DELETE FROM item_changes
|
||||
WHERE id <= ?
|
||||
AND created_time <= ?
|
||||
`, [lowestChangeId, cutOffDate]);
|
||||
}
|
||||
|
||||
public static async changesSinceId(changeId: number, options: ChangeSinceIdOptions = null): Promise<ItemChangeEntity[]> {
|
||||
options = {
|
||||
limit: 100,
|
||||
fields: ['id', 'item_type', 'item_id', 'type', 'created_time'],
|
||||
...options,
|
||||
};
|
||||
|
||||
return this.db().selectAll(`
|
||||
SELECT ${this.db().escapeFieldsToString(options.fields)}
|
||||
FROM item_changes
|
||||
WHERE id > ?
|
||||
ORDER BY id
|
||||
LIMIT ?
|
||||
`, [changeId, options.limit]);
|
||||
}
|
||||
|
||||
}
|
||||
|
Reference in New Issue
Block a user