diff --git a/index.js b/index.js index 5512d8e..93c8795 100644 --- a/index.js +++ b/index.js @@ -7,6 +7,7 @@ import assert from 'assert' * @property {string} versionId * @property {string[]} links * @property {string} updatedAt + * @property {Boolean} deleted */ /** @typedef {{ type: string, pk: 1 | 0, cid: number, notnull: 1 | 0, dflt_value: any, name: string }} ColumnInfo */ @@ -28,6 +29,7 @@ const docSchema = { links: { type: 'TEXT', notnull: 1, dflt_value: null, pk: 0 }, forks: { type: 'TEXT', notnull: 1, dflt_value: null, pk: 0 }, updatedAt: { type: 'TEXT', notnull: 1, pk: 0 }, + deleted: { type: 'INTEGER', notnull: 1, pk: 0 }, } /** @type {ColumnSchema} */ @@ -70,7 +72,7 @@ export class DbApi { ) const docColumns = tableInfo.map(({ name }) => name) this.#getDocSql = db.prepare( - `SELECT docId, versionId, links, forks, updatedAt + `SELECT docId, versionId, links, forks, updatedAt, deleted FROM ${docTableName} WHERE docId = ?` ) diff --git a/test/complex-docs.js b/test/complex-docs.js index 38936f5..037cf43 100644 --- a/test/complex-docs.js +++ b/test/complex-docs.js @@ -13,6 +13,7 @@ test('booleans, arrays and objects are transformed', async (t) => { boolean: true, array: [], object: {}, + deleted: false, }, { docId: 'B', @@ -22,8 +23,17 @@ test('booleans, arrays and objects are transformed', async (t) => { boolean: false, array: ['foo'], object: { foo: 'bar' }, + deleted: false, + }, + { + docId: 'C', + versionId: '1', + links: [], + updatedAt, + array: [], + object: {}, + deleted: false, }, - { docId: 'C', versionId: '1', links: [], updatedAt, array: [], object: {} }, ] const extraColumns = ` @@ -45,6 +55,7 @@ object TEXT NOT NULL` boolean: 1, array: '[]', object: '{}', + deleted: 0, }, { docId: 'B', @@ -55,6 +66,7 @@ object TEXT NOT NULL` boolean: 0, array: '["foo"]', object: '{"foo":"bar"}', + deleted: 0, }, { docId: 'C', @@ -65,6 +77,7 @@ object TEXT NOT NULL` boolean: 0, array: '[]', object: '{}', + deleted: 0, }, ] diff --git a/test/index-callback.js b/test/index-callback.js index fa9c5ee..6b396fc 100644 --- a/test/index-callback.js +++ b/test/index-callback.js @@ -3,14 +3,70 @@ import test from 'tape' import { create } from './utils.js' const docs = [ - { docId: 'A', seq: 1, versionId: '1', links: [], updatedAt: '' }, - { docId: 'A', seq: 2, versionId: '2', links: ['1'], updatedAt: '' }, - { docId: 'A', seq: 3, versionId: '3', links: ['1'], updatedAt: '' }, - { docId: 'A', seq: 4, versionId: '4', links: ['2', '3'], updatedAt: '' }, - { docId: 'A', seq: 5, versionId: '5', links: ['4'], updatedAt: '' }, - { docId: 'A', seq: 6, versionId: '6', links: ['4'], updatedAt: '' }, - { docId: 'A', seq: 7, versionId: '7', links: ['4'], updatedAt: '' }, - { docId: 'A', seq: 8, versionId: '8', links: ['5', '6'], updatedAt: '' }, + { + docId: 'A', + seq: 1, + versionId: '1', + links: [], + updatedAt: '', + deleted: false, + }, + { + docId: 'A', + seq: 2, + versionId: '2', + links: ['1'], + updatedAt: '', + deleted: false, + }, + { + docId: 'A', + seq: 3, + versionId: '3', + links: ['1'], + updatedAt: '', + deleted: false, + }, + { + docId: 'A', + seq: 4, + versionId: '4', + links: ['2', '3'], + updatedAt: '', + deleted: false, + }, + { + docId: 'A', + seq: 5, + versionId: '5', + links: ['4'], + updatedAt: '', + deleted: false, + }, + { + docId: 'A', + seq: 6, + versionId: '6', + links: ['4'], + updatedAt: '', + deleted: false, + }, + { + docId: 'A', + seq: 7, + versionId: '7', + links: ['4'], + updatedAt: '', + deleted: false, + }, + { + docId: 'A', + seq: 8, + versionId: '8', + links: ['5', '6'], + updatedAt: '', + deleted: false, + }, ] test('onceWriteDoc called for each doc', async (t) => { diff --git a/test/scenarios.js b/test/scenarios.js index 8470f12..08692fe 100644 --- a/test/scenarios.js +++ b/test/scenarios.js @@ -3,14 +3,26 @@ import test from 'tape' import { create, permute } from './utils.js' const docs = [ - { docId: 'A', versionId: '1', links: [], updatedAt: '' }, - { docId: 'A', versionId: '2', links: ['1'], updatedAt: '' }, - { docId: 'A', versionId: '3', links: ['1'], updatedAt: '' }, - { docId: 'A', versionId: '4', links: ['2', '3'], updatedAt: '' }, - { docId: 'A', versionId: '5', links: ['4'], updatedAt: '' }, - { docId: 'A', versionId: '6', links: ['4'], updatedAt: '' }, - { docId: 'A', versionId: '7', links: ['4'], updatedAt: '' }, - { docId: 'A', versionId: '8', links: ['5', '6'], updatedAt: '' }, + { docId: 'A', versionId: '1', links: [], updatedAt: '', deleted: false }, + { docId: 'A', versionId: '2', links: ['1'], updatedAt: '', deleted: false }, + { docId: 'A', versionId: '3', links: ['1'], updatedAt: '', deleted: false }, + { + docId: 'A', + versionId: '4', + links: ['2', '3'], + updatedAt: '', + deleted: false, + }, + { docId: 'A', versionId: '5', links: ['4'], updatedAt: '', deleted: false }, + { docId: 'A', versionId: '6', links: ['4'], updatedAt: '', deleted: false }, + { docId: 'A', versionId: '7', links: ['4'], updatedAt: '', deleted: true }, + { + docId: 'A', + versionId: '8', + links: ['5', '6'], + updatedAt: '', + deleted: true, + }, ] const scenarios = [ @@ -22,6 +34,7 @@ const scenarios = [ links: ['1'], forks: [], updatedAt: '', + deleted: 0, }, }, { @@ -32,6 +45,7 @@ const scenarios = [ links: ['1'], forks: ['2'], updatedAt: '', + deleted: 0, }, }, { @@ -42,6 +56,7 @@ const scenarios = [ links: ['2', '3'], forks: [], updatedAt: '', + deleted: 0, }, }, { @@ -52,6 +67,7 @@ const scenarios = [ links: ['4'], forks: [], updatedAt: '', + deleted: 0, }, }, { @@ -62,6 +78,7 @@ const scenarios = [ links: ['4'], forks: ['5'], updatedAt: '', + deleted: 0, }, }, { @@ -72,6 +89,7 @@ const scenarios = [ links: ['4'], forks: ['5', '6'], updatedAt: '', + deleted: 1, }, }, { @@ -82,6 +100,7 @@ const scenarios = [ links: ['5', '6'], forks: ['7'], updatedAt: '', + deleted: 1, }, }, ] diff --git a/test/timestamps.js b/test/timestamps.js index f05098e..9a41ae8 100644 --- a/test/timestamps.js +++ b/test/timestamps.js @@ -7,12 +7,48 @@ test('If doc has timestamp, it is used to select winner', async (t) => { const updated2 = new Date(1999, 0, 2).toISOString() const updated3 = new Date(1999, 0, 3).toISOString() const docs = [ - { docId: 'A', versionId: '1', links: [], updatedAt: updated3 }, - { docId: 'A', versionId: '2', links: ['1'], updatedAt: updated2 }, - { docId: 'A', versionId: '3', links: ['1'], updatedAt: updated1 }, - { docId: 'B', versionId: '1', links: [], updatedAt: updated3 }, - { docId: 'B', versionId: '2', links: ['1'], updatedAt: updated1 }, - { docId: 'B', versionId: '3', links: ['1'], updatedAt: updated2 }, + { + docId: 'A', + versionId: '1', + links: [], + updatedAt: updated3, + deleted: false, + }, + { + docId: 'A', + versionId: '2', + links: ['1'], + updatedAt: updated2, + deleted: false, + }, + { + docId: 'A', + versionId: '3', + links: ['1'], + updatedAt: updated1, + deleted: false, + }, + { + docId: 'B', + versionId: '1', + links: [], + updatedAt: updated3, + deleted: false, + }, + { + docId: 'B', + versionId: '2', + links: ['1'], + updatedAt: updated1, + deleted: false, + }, + { + docId: 'B', + versionId: '3', + links: ['1'], + updatedAt: updated2, + deleted: false, + }, ] const { indexer, api, cleanup } = create({ extraColumns: 'timestamp NUMBER' }) @@ -25,6 +61,7 @@ test('If doc has timestamp, it is used to select winner', async (t) => { versionId: '2', links: ['1'], forks: ['3'], + deleted: 0, } const head = api.getDoc(expected.docId) @@ -40,6 +77,7 @@ test('If doc has timestamp, it is used to select winner', async (t) => { versionId: '3', links: ['1'], forks: ['2'], + deleted: 0, } const head = api.getDoc(expected.docId) @@ -55,9 +93,9 @@ test('If doc has timestamp, it is used to select winner', async (t) => { test('If doc has no timestamp, version is used to select a deterministic winner', async (t) => { const updatedAt = new Date().toISOString() const docs = [ - { docId: 'A', versionId: '1', links: [], updatedAt }, - { docId: 'A', versionId: '2', links: ['1'], updatedAt }, - { docId: 'A', versionId: '3', links: ['1'], updatedAt }, + { docId: 'A', versionId: '1', links: [], updatedAt, deleted: false }, + { docId: 'A', versionId: '2', links: ['1'], updatedAt, deleted: false }, + { docId: 'A', versionId: '3', links: ['1'], updatedAt, deleted: false }, ] const { indexer, api, cleanup } = create() @@ -67,6 +105,7 @@ test('If doc has no timestamp, version is used to select a deterministic winner' versionId: '3', links: ['1'], forks: ['2'], + deleted: 0, } indexer.batch(docs) diff --git a/test/utils.js b/test/utils.js index 5b6dd08..6ca9b78 100644 --- a/test/utils.js +++ b/test/utils.js @@ -17,7 +17,8 @@ export function create({ extraColumns = '' } = {}) { versionId TEXT NOT NULL, links TEXT NOT NULL, forks TEXT NOT NULL, - updatedAt TEXT NOT NULL + updatedAt TEXT NOT NULL, + deleted INTEGER NOT NULL ${extraColumns ? ', ' + extraColumns : ''} ) WITHOUT ROWID`