deno.land / x / replicache@v10.0.0-beta.0 / db / write.test.ts
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279import {LogContext} from '@rocicorp/logger';import {expect} from '@esm-bundle/chai';import {assertNotUndefined} from '../asserts';import * as dag from '../dag/mod';import {DEFAULT_HEAD_NAME} from './commit';import { readCommit, readCommitForBTreeRead, readIndexesForRead, whenceHead,} from './read';import {initDB, Write} from './write';import {encodeIndexKey} from './index';import {asyncIterableToArray} from '../async-iterable-to-array';import {BTreeRead} from '../btree/mod';
test('basics', async () => { const ds = new dag.TestStore(); const lc = new LogContext(); await initDB(await ds.write(), DEFAULT_HEAD_NAME);
// Put. await ds.withWrite(async dagWrite => { const w = await Write.newLocal( whenceHead(DEFAULT_HEAD_NAME), 'mutator_name', JSON.stringify([]), null, dagWrite, 42, ); await w.put(lc, 'foo', 'bar'); // Assert we can read the same value from within this transaction.; const val = await w.get('foo'); expect(val).to.deep.equal('bar'); await w.commit(DEFAULT_HEAD_NAME); });
// As well as after it has committed. await ds.withWrite(async dagWrite => { const w = await Write.newLocal( whenceHead(DEFAULT_HEAD_NAME), 'mutator_name', JSON.stringify(null), null, dagWrite, 42, ); const val = await w.get('foo'); expect(val).to.deep.equal('bar'); });
// Del. await ds.withWrite(async dagWrite => { const w = await Write.newLocal( whenceHead(DEFAULT_HEAD_NAME), 'mutator_name', JSON.stringify([]), null, dagWrite, 42, ); await w.del(lc, 'foo'); // Assert it is gone while still within this transaction. const val = await w.get('foo'); expect(val).to.be.undefined; await w.commit(DEFAULT_HEAD_NAME); });
// As well as after it has committed. await ds.withWrite(async dagWrite => { const w = await Write.newLocal( whenceHead(DEFAULT_HEAD_NAME), 'mutator_name', JSON.stringify(null), null, dagWrite, 42, ); const val = await w.get(`foo`); expect(val).to.be.undefined; });});
test('index commit type constraints', async () => { const ds = new dag.TestStore(); const lc = new LogContext(); await initDB(await ds.write(), DEFAULT_HEAD_NAME);
// Test that local changes cannot create or drop an index. const w = await Write.newLocal( whenceHead(DEFAULT_HEAD_NAME), 'mutator_name', JSON.stringify([]), null, await ds.write(), 42, );
let err; try { await w.createIndex(lc, 'foo', '', ''); } catch (e) { err = e; } expect(err).to.be.an.instanceof(Error); expect(err).to.have.property('message', 'Not allowed');
err = undefined; try { await w.dropIndex('foo'); } catch (e) { err = e; } expect(err).to.be.an.instanceof(Error); expect(err).to.have.property('message', 'Not allowed');});
test('clear', async () => { const ds = new dag.TestStore(); const lc = new LogContext(); await ds.withWrite(dagWrite => initDB(dagWrite, DEFAULT_HEAD_NAME)); await ds.withWrite(async dagWrite => { const w = await Write.newLocal( whenceHead(DEFAULT_HEAD_NAME), 'mutator_name', JSON.stringify([]), null, dagWrite, 42, ); await w.put(lc, 'foo', 'bar'); await w.commit(DEFAULT_HEAD_NAME); });
await ds.withWrite(async dagWrite => { const w = await Write.newIndexChange( whenceHead(DEFAULT_HEAD_NAME), dagWrite, ); await w.createIndex(lc, 'idx', '', ''); await w.commit(DEFAULT_HEAD_NAME); });
await ds.withWrite(async dagWrite => { const w = await Write.newLocal( whenceHead(DEFAULT_HEAD_NAME), 'mutator_name', JSON.stringify([]), null, dagWrite, 42, ); await w.put(lc, 'hot', 'dog');
const keys = await asyncIterableToArray(w.map.keys()); expect(keys).to.have.lengthOf(2); let index = w.indexes.get('idx'); assertNotUndefined(index); await index.withMap(dagWrite, async map => { const keys = await asyncIterableToArray(map.keys()); expect(keys).to.have.lengthOf(2); });
await w.clear(); const keys2 = await asyncIterableToArray(w.map.keys()); expect(keys2).to.have.lengthOf(0); index = w.indexes.get('idx'); assertNotUndefined(index); await index.withMap(dagWrite, async map => { const keys = await asyncIterableToArray(map.keys()); expect(keys).to.have.lengthOf(0); });
await w.commit(DEFAULT_HEAD_NAME); });
await ds.withRead(async dagRead => { const [, c, r] = await readCommitForBTreeRead( whenceHead(DEFAULT_HEAD_NAME), dagRead, ); const indexes = readIndexesForRead(c); const keys = await asyncIterableToArray(r.keys()); expect(keys).to.have.lengthOf(0); const index = indexes.get('idx'); assertNotUndefined(index); await index.withMap(dagRead, async map => { const keys = await asyncIterableToArray(map.keys()); expect(keys).to.have.lengthOf(0); }); });});
test('create and drop index', async () => { const t = async (writeBeforeIndexing: boolean) => { const ds = new dag.TestStore(); const lc = new LogContext(); await ds.withWrite(dagWrite => initDB(dagWrite, DEFAULT_HEAD_NAME));
if (writeBeforeIndexing) { await ds.withWrite(async dagWrite => { const w = await Write.newLocal( whenceHead(DEFAULT_HEAD_NAME), 'mutator_name', JSON.stringify([]), null, dagWrite, 42, ); for (let i = 0; i < 3; i++) { await w.put(lc, `k${i}`, {s: `s${i}`}); } await w.commit(DEFAULT_HEAD_NAME); }); }
const indexName = 'i1'; await ds.withWrite(async dagWrite => { const w = await Write.newIndexChange( whenceHead(DEFAULT_HEAD_NAME), dagWrite, ); await w.createIndex(lc, indexName, '', '/s'); await w.commit(DEFAULT_HEAD_NAME); });
if (!writeBeforeIndexing) { await ds.withWrite(async dagWrite => { const w = await Write.newLocal( whenceHead(DEFAULT_HEAD_NAME), 'mutator_name', JSON.stringify([]), null, dagWrite, 42, ); for (let i = 0; i < 3; i++) { await w.put(lc, `k${i}`, {s: `s${i}`}); } await w.commit(DEFAULT_HEAD_NAME); }); }
await ds.withRead(async dagRead => { const [, c] = await readCommit(whenceHead(DEFAULT_HEAD_NAME), dagRead); const {indexes} = c; expect(indexes).to.have.lengthOf(1); const idx = indexes[0]; expect(idx.definition.name).to.equal(indexName); expect(idx.definition.keyPrefix).to.be.empty; expect(idx.definition.jsonPointer).to.equal('/s'); const indexMap = new BTreeRead(dagRead, idx.valueHash);
const entries = await asyncIterableToArray(indexMap); expect(entries).to.have.lengthOf(3); for (let i = 0; i < 3; i++) { expect(entries[i][0]).to.deep.equal(encodeIndexKey([`s${i}`, `k${i}`])); } });
// Ensure drop works. await ds.withWrite(async dagWrite => { const w = await Write.newIndexChange( whenceHead(DEFAULT_HEAD_NAME), dagWrite, ); await w.dropIndex(indexName); await w.commit(DEFAULT_HEAD_NAME); const [, c] = await readCommit(whenceHead(DEFAULT_HEAD_NAME), dagWrite); const {indexes} = c; expect(indexes).to.be.empty; }); };
await t(true); await t(false);});
Version Info