Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# CLAUDE.md

## Build & Test

- **Tests:** `npx vitest run` (run all tests) or `npx vitest run test/<file>` (run a single test file)
- **Lint:** `npm run lint` (uses [standard](https://standardjs.com/) — no semicolons, no trailing commas)

## Conventions

- All changes should include tests where possible
- Tests must pass before submitting
- Lint must pass before submitting
5 changes: 5 additions & 0 deletions src/batch/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,11 @@ export interface Batcher {
* overwritten.
*/
put: (key: string, value: UnknownLink) => Promise<void>
/**
* Delete the value for the given key. If the key is not found no operation
* occurs.
*/
del: (key: string) => Promise<void>
/**
* Encode all altered shards in the batch and return the new root CID and
* difference blocks.
Expand Down
34 changes: 34 additions & 0 deletions src/batch/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,15 @@ class Batcher {
return put(this.blocks, this, key, value)
}

/**
* @param {string} key The key of the value to delete.
* @returns {Promise<void>}
*/
async del (key) {
if (this.#committed) throw new BatchCommittedError()
return del(this.blocks, this, key)
}

async commit () {
if (this.#committed) throw new BatchCommittedError()
this.#committed = true
Expand Down Expand Up @@ -165,6 +174,31 @@ export const put = async (blocks, shard, key, value) => {
shard.entries = Shard.putEntry(asShardEntries(targetEntries), asShardEntry(entry))
}

/**
* @param {API.BlockFetcher} blocks
* @param {API.BatcherShard} shard
* @param {string} key The key of the value to delete.
* @returns {Promise<void>}
*/
export const del = async (blocks, shard, key) => {
const shards = new ShardFetcher(blocks)
const dest = await traverse(shards, shard, key)

const entryidx = dest.shard.entries.findIndex(([k]) => k === dest.key)
if (entryidx === -1) return

const entry = dest.shard.entries[entryidx]
if (Array.isArray(entry[1])) {
// cannot delete a shard-only entry (no value)
if (entry[1][1] == null) return
// remove value but keep shard link
dest.shard.entries[entryidx] = [entry[0], /** @type {API.ShardEntryLinkValue | API.ShardEntryShardValue} */ ([entry[1][0]])]
} else {
// remove the entry entirely
dest.shard.entries.splice(entryidx, 1)
}
}

/**
* Traverse from the passed shard through to the correct shard for the passed
* key.
Expand Down
10 changes: 10 additions & 0 deletions src/crdt/batch/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,16 @@ class Batcher {
this.ops.push({ type: 'put', key, value })
}

/**
* @param {string} key The key of the value to delete.
* @returns {Promise<void>}
*/
async del (key) {
if (this.#committed) throw new BatchCommittedError()
await Batch.del(this.blocks, this, key)
this.ops.push({ type: 'del', key })
}

async commit () {
if (this.#committed) throw new BatchCommittedError()
this.#committed = true
Expand Down
Loading