@cloudbitmaps/roaring 0.19.1 → 0.20.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -13,7 +13,7 @@
13
13
  * which it reads back to verify. A refusal here comes from a read, and in an erasure the reads that can be refused
14
14
  * come before the deletes.
15
15
  */
16
- import type { GenKey, IStorageDriver, SegmentRef } from '@cloudbitmaps/core';
16
+ import type { GenKey, IStorageDriver, SegmentRef, StorageDeleteOptions } from '@cloudbitmaps/core';
17
17
  export declare class OpenChargingStorage implements IStorageDriver {
18
18
  private readonly inner;
19
19
  private readonly charge;
@@ -29,6 +29,7 @@ export declare class OpenChargingStorage implements IStorageDriver {
29
29
  getRange(key: GenKey, offset: number, length: number): Promise<Uint8Array>;
30
30
  /** One `getTail` is one open: a reader takes the footer and the index from it, and reads chunks with `getRange`. */
31
31
  getTail(key: GenKey, maxBytes: number): ReturnType<IStorageDriver['getTail']>;
32
- delete(key: GenKey): Promise<void>;
32
+ /** Handed through whole: the erasure's delete of a holder is conditioned on the object it searched. */
33
+ delete(key: GenKey, options?: StorageDeleteOptions): Promise<void>;
33
34
  list(ref: SegmentRef): AsyncIterable<GenKey>;
34
35
  }
@@ -15,13 +15,13 @@ export declare function storageChunkSourceConformance(label: string, makeSource:
15
15
  bitmap: SafeBitmap;
16
16
  }>) => Promise<StorageChunkSource>): void;
17
17
  /** The storage-driver cases {@link storageDriverConformance} runs; an emulator that cannot model one skips it by name. */
18
- export type StorageDriverCase = 'write-once round trip' | 'collision' | 'collision on a large upload' | 'missing object' | 'out-of-range read' | 'tail size' | 'idempotent delete' | 'delete of an absent key beside its neighbours' | 'list read-after-delete' | 'names and namespaces kept apart' | 'generations by number' | 'failed write' | 'missing location' | 'list across pages';
18
+ export type StorageDriverCase = 'write-once round trip' | 'collision' | 'collision on a large upload' | 'missing object' | 'out-of-range read' | 'tail size' | 'idempotent delete' | 'delete of an absent key beside its neighbours' | 'list read-after-delete' | 'names and namespaces kept apart' | 'generations by number' | 'failed write' | 'missing location' | 'list across pages' | 'conditional delete';
19
19
  /**
20
20
  * Contract tests for an {@link IStorageDriver} — the contract its doc comment lists: write-once with
21
21
  * `WriteConflictError` on a collision, `NotFoundError` for a missing object, `ValidationError` for an out-of-range
22
- * read, `getTail`'s true total size, idempotent `delete` (of an absent key too, with neighbours present), and a `list`
23
- * that is read-after-delete. `makeDriver` MUST
24
- * return a driver over an empty, isolated keyspace on each call.
22
+ * read, `getTail`'s true total size, idempotent `delete` (of an absent key too, with neighbours present), a `list`
23
+ * that is read-after-delete, and a `delete` given `ifVersion` that does what `conditionalDelete` says. `makeDriver`
24
+ * MUST return a driver over an empty, isolated keyspace on each call.
25
25
  *
26
26
  * `skip` names the cases a backend cannot exercise (a local emulator that does not model a contract), so each
27
27
  * skip is visible at the call site, with the reason beside it, rather than hidden in a weakened assertion.
@@ -47,6 +47,13 @@ export declare function storageDriverConformance(label: string, makeDriver: () =
47
47
  * driver that drops its continuation token fails. Omitted, the case does not run.
48
48
  */
49
49
  readonly pagedListSize?: number;
50
+ /**
51
+ * What the driver under test reports as `capabilities().conditionalDelete` once it has made a delete given
52
+ * `ifVersion`, which is when a driver that resolves it lazily has resolved it. Stated at the call site, so a driver
53
+ * that stops applying the condition fails here rather than being exempted by its own report. Omitted, the case
54
+ * holds the driver to whatever it reports.
55
+ */
56
+ readonly conditionalDelete?: boolean;
50
57
  }): void;
51
58
  /**
52
59
  * Contract tests for an {@link IRegistryDriver}. `makeDriver` MUST return a fresh, empty, isolated driver on
@@ -92,8 +99,8 @@ export interface RegistryDeleteHarness {
92
99
  /** Whether the backend holds anything for `ref`: a live row, or the tombstone a delete left in its place. */
93
100
  stored(ref: SegmentRef): Promise<boolean>;
94
101
  /**
95
- * Put `text` at `ref`'s row, as another writer left it: here, a row as a release before 0.12 wrote it. Omitted by
96
- * a registry that persists nothing a test can plant (the in-memory one).
102
+ * Put `text` at `ref`'s row, as another writer left it: here, a row stamped with an earlier schema. Omitted by a
103
+ * registry that persists nothing a test can plant (the in-memory one).
97
104
  */
98
105
  plantRow?(ref: SegmentRef, text: string): Promise<void>;
99
106
  }
@@ -101,10 +108,8 @@ export interface RegistryDeleteHarness {
101
108
  * Contract tests for what `delete` leaves behind, which differs by driver and is declared by
102
109
  * `capabilities().conditionalDelete`:
103
110
  *
104
- * - **`true`**: a delete removes a row whose token carries an incarnation id from the backend for good, and does so
105
- * only while the row is still the version it read. A row a release before 0.12 wrote has a bare decimal token and
106
- * is tombstoned, never removed: a process still on that release, re-creating the name over nothing, would issue
107
- * those same counters again from 0.
111
+ * - **`true`**: a delete removes the row from the backend for good, and does so only while the row is still the
112
+ * version it read.
108
113
  * - **`false` or absent**: every delete leaves a tombstone, which a later full listing still reads.
109
114
  *
110
115
  * Either way `get` answers `null` afterwards, `list` skips the row, and a name created again is a new incarnation that
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cloudbitmaps/roaring",
3
- "version": "0.19.1",
3
+ "version": "0.20.0",
4
4
  "description": "Distributed, cloud-native Roaring Bitmaps — query and intersect billion-scale integer sets straight out of object storage, from a bounded RAM cache over immutable objects in your own bucket, at a fraction of an always-on cache.",
5
5
  "keywords": [
6
6
  "roaring",
@@ -65,7 +65,7 @@
65
65
  },
66
66
  "dependencies": {
67
67
  "roaring": "2.7.0",
68
- "@cloudbitmaps/core": "^0.19.1"
68
+ "@cloudbitmaps/core": "^0.20.0"
69
69
  },
70
70
  "devDependencies": {
71
71
  "@types/node": "^22.0.0",