max: {
major: 1,
minor: 0,
- patch: 2,
+ patch: 3,
},
};
if (result.rowCount != 1) {
throw new DBErrors.UnexpectedResult('did not set topic content');
}
+ result = await dbCtx.result(this.statement.topicSetContentHistory, { topicId: data.topicId, contentHash: data.contentHash, contentSize: data.content.length });
+ if (result.rowCount != 1) {
+ throw new DBErrors.UnexpectedResult('did not set topic content history');
+ }
this.logger.debug(_scope, 'success', { ...logData });
return this._engineInfo(result);
} catch (e) {
--- /dev/null
+BEGIN;
+ -- Track all content updates over time.
+ CREATE TABLE topic_content_history (
+ topic_id UUID NOT NULL REFERENCES topic(id) ON DELETE CASCADE ON UPDATE CASCADE DEFERRABLE INITIALLY DEFERRED,
+ content_updated TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(),
+ content_size INTEGER NOT NULL,
+ content_hash TEXT NOT NULL
+ );
+ CREATE INDEX topic_content_history_topic_id_idx ON topic_content_history(topic_id);
+ CREATE INDEX topic_content_history_content_updated_idx ON topic_content_history(content_updated);
+
+ INSERT INTO _meta_schema_version (major, minor, patch) VALUES (1, 0, 3);
+COMMIT;
--- /dev/null
+BEGIN;
+ DROP INDEX topic_content_history_topic_id_idx;
+ DROP INDEX topic_content_history_content_updated_idx;
+ DROP TABLE topic_content_history;
+
+ DELETE FROM _meta_schema_version WHERE major = 1 AND minor = 0 AND patch = 3;
+COMMIT;
--- /dev/null
+--
+INSERT INTO topic_content_history
+ (topic_id, content_size, content_hash)
+VALUES
+ ($(topicId), $(contentSize), $(contentHash))
max: {
major: 1,
minor: 0,
- patch: 2,
+ patch: 3,
},
};
if (result.changes != 1) {
throw new DBErrors.UnexpectedResult('did not set topic content');
}
+ result = this.statement.topicSetContentHistory.run({ topicId: data.topicId, contentHash: data.contentHash, contentSize: data.content.length });
+ if (result.changes != 1) {
+ throw new DBErrors.UnexpectedResult('did not set topic content history');
+ }
return this._engineInfo(result);
} catch (e) {
this.logger.error(_scope, 'failed', { error: e, ...logData });
--- /dev/null
+BEGIN;
+ -- Track all content updates over time.
+ CREATE TABLE topic_content_history (
+ topic_id INTEGER NOT NULL REFERENCES topic(id) ON DELETE CASCADE ON UPDATE CASCADE DEFERRABLE INITIALLY DEFERRED,
+ content_updated INTEGER NOT NULL DEFAULT (strftime('%s', 'now')),
+ content_size INTEGER NOT NULL,
+ content_hash TEXT NOT NULL
+ );
+ CREATE INDEX topic_content_history_topic_id_idx ON topic_content_history(topic_id);
+ CREATE INDEX topic_content_history_content_updated_idx ON topic_content_history(content_updated);
+
+ INSERT INTO _meta_schema_version (major, minor, patch) VALUES (1, 0, 3);
+COMMIT;
--- /dev/null
+BEGIN;
+ DROP INDEX topic_content_history_topic_id_idx;
+ DROP INDEX topic_content_history_content_updated_idx;
+ DROP TABLE topic_content_history;
+
+ DELETE FROM _meta_schema_version WHERE major = 1 AND minor = 0 AND patch = 3;
+COMMIT;
--- /dev/null
+--
+INSERT INTO topic_content_history
+ (topic_id, content_size, content_hash)
+VALUES
+ (:topicId, :contentSize, :contentHash)
contentType: 'text/plain',
contentHash: 'abc123',
};
+ sinon.stub(db.db, 'result');
});
it('success', async function() {
const dbResult = {
lastInsertRowid: undefined,
duration: 10,
};
- sinon.stub(db.db, 'result').resolves(dbResult);
+ db.db.result.resolves(dbResult);
const result = await db.topicSetContent(dbCtx, data);
assert.deepStrictEqual(result, expected);
});
rows: [],
duration: 10,
};
- sinon.stub(db.db, 'result').resolves(dbResult);
+ db.db.result.resolves(dbResult);
+ try {
+ await db.topicSetContent(dbCtx, data);
+ assert.fail(noExpectedException);
+ } catch (e) {
+ assert(e instanceof DBErrors.UnexpectedResult);
+ }
+ });
+ it('failure 2', async function () {
+ const dbResultSuccess = {
+ rowCount: 1,
+ rows: [],
+ duration: 10,
+ };
+ const dbResultFail = {
+ rowCount: 0,
+ rows: [],
+ duration: 10,
+ };
+ db.db.result
+ .onCall(0).resolves(dbResultSuccess)
+ .onCall(1).resolves(dbResultFail);
try {
await db.topicSetContent(dbCtx, data);
assert.fail(noExpectedException);
contentType: 'text/plain',
contentHash: 'abc123',
};
+ sinon.stub(db.statement.topicSetContent, 'run');
+ sinon.stub(db.statement.topicSetContentHistory, 'run');
});
it('success', async function() {
const dbResult = {
changes: 1,
lastInsertRowid: undefined,
};
- sinon.stub(db.statement.topicSetContent, 'run').returns(dbResult);
+ db.statement.topicSetContent.run.returns(dbResult);
+ db.statement.topicSetContentHistory.run.returns(dbResult);
const result = await db.topicSetContent(dbCtx, data);
assert.deepStrictEqual(result, expected);
});
changes: 0,
lastInsertRowid: undefined,
};
- sinon.stub(db.statement.topicSetContent, 'run').returns(dbResult);
+ db.statement.topicSetContent.run.returns(dbResult);
+ try {
+ await db.topicSetContent(dbCtx, data);
+ assert.fail(noExpectedException);
+ } catch (e) {
+ assert(e instanceof DBErrors.UnexpectedResult);
+ }
+ });
+ it('failure 2', async function () {
+ const dbResultSuccess = {
+ changes: 1,
+ lastInsertRowid: undefined,
+ };
+ const dbResultFail = {
+ changes: 0,
+ lastInsertRowid: undefined,
+ };
+ db.statement.topicSetContent.run.returns(dbResultSuccess);
+ db.statement.topicSetContentHistory.run.returns(dbResultFail);
try {
await db.topicSetContent(dbCtx, data);
assert.fail(noExpectedException);