Releases: veeso/wasm-dbms
wasm-dbms 0.9.0
0.9.0
Released on 2026-04-28
⚠ Breaking Changes
Added
- query: add DISTINCT support to query API
Adds
distinct_byfield onQueryand.distinct(&[..])builder method.
The select pipeline deduplicates rows by the listed columns before applying
ORDER BY / OFFSET / LIMIT, matching standard SQL semantics. Closes #85. - query: add aggregates, GROUP BY, and HAVING (#86)
Introduce
Database::aggregatewith COUNT/SUM/AVG/MIN/MAX, GROUP BY,
HAVING, and aggregate-aware ORDER BY/LIMIT/OFFSET. Expose the new flow
through the IC canister macro (aggregate_<table>) and the
ic-dbms-clientClient trait + all three client impls.- AggregateFunction / AggregatedRow / AggregatedValue types in
wasm-dbms-api; HAVING / ORDER BY reference aggregate outputs by
synthetic agg{N} names. - Plan-time validation: SUM/AVG numeric, unknown col/agg, LIKE/JSON
rejected in HAVING, joins/eager relations rejected in aggregate. - Reject group_by/having on non-aggregate select paths via new
QueryError::AggregateClauseInSelect (mirrors JoinInsideTypedSelect). - Fix Query candid serialization order after group_by/having insertion
(idl_hash-sorted: eager_relations, distinct_by, joins, offset, limit,
filter, group_by, having, order_by, columns). - Tests: 29 unit tests, 3 select-guard tests, 6 pocket-ic integration
tests including round-trip via wrapper canister. - Docs: guides/querying.md aggregations section, reference/query.md
Aggregate Types + Errors, ic/reference/schema.md endpoint listing,
ic/guides/client-api.md client.aggregate example, errors.md updates. - Database trait method docs rewritten with proper Errors sections.
- AggregateFunction / AggregatedRow / AggregatedValue types in
- migrations: add schema snapshot, Migrate trait, and macro support (#34)
Lay the groundwork for schema migrations:
- Snapshot types (
TableSchemaSnapshot,ColumnSnapshot,IndexSnapshot,
ForeignKeySnapshot,OnDeleteSnapshot,DataTypeSnapshot) with
versioned binaryEncode/Decode,Serialize/Deserialize, and
feature-gatedCandidTypederives. TableSchema::schema_snapshot()with default impl assembling from
table_name/primary_key/columns/indexesand
Encode::ALIGNMENT.dbms::migrationmodule:Migratetrait,MigrationOp,ColumnChanges,
MigrationPolicy,MigrationError, plusDbmsError::Migrationand
prelude re-exports.ColumnDefgainsdefault: Option<fn() -> Value>(kept fn-pointer to
preserveCopy) andrenamed_from: &'static [&'static str].#[derive(Table)]parses#[default = ...],#[renamed_from(...)], and
#[migrate]; emitsimpl Migrate for T {}unless#[migrate]is set.DatabaseSchematrait and#[derive(DatabaseSchema)]gain
migrate_default,migrate_transform,compiled_snapshotsdispatch
methods (object-safe viaSelf: Sized).- WIT: new
migration-error(string)variant; guest maps
DbmsError::Migration. - Docs: schema reference covers the three new attributes; new
docs/reference/migrations.mdanddocs/guides/migrations.md; errors
reference lists everyMigrationErrorvariant. - Tests: 13 new macro tests cover
#[default],#[renamed_from],
#[migrate], dispatch fall-through, unknown-table behaviour, and
multi-table snapshot ordering.
Memory layer integration, the migration engine,
Databasewiring, IC
endpoints, client surface, integration tests, and full WIT migrate APIs
are tracked in the issue checklist. - Snapshot types (
- migrations: name-hash fingerprint + schema snapshot ledger
Switch
TableSchema::fingerprintto hashtable_name()instead of
TypeIdso table identity stays stable across rebuilds and schema
evolution.SchemaRegistry::register_tablenow detects name-hash
collisions eagerly: when the fingerprint slot is occupied, it loads the
persisted snapshot and compares names, returning the new
MemoryError::NameCollisionvariant on mismatch.Wire
SchemaSnapshotLedgerinto the registry:register_table
initializes the snapshot on the dedicated page, and the encode/decode of
SchemaRegistrynow persistsschema_snapshot_page. Add full module-,
struct-, and method-level docs toSchemaSnapshotLedgerplus coverage
tests for init/load/write/get and page isolation.Update
docs/technical/memory.mdwith the new per-table snapshot page,
the name-hash fingerprint semantics, the collision-detection flow, the
ledger API, and theTableSchemaSnapshotserialization layout. - migrations: engine + Database wiring for schema migrations
Wire the migration engine into the generic
wasm-dbmscrate so callers
can detect drift, plan migrations, and apply structural ops through the
existingDatabasetrait surface.Engine layer (
crates/wasm-dbms/wasm-dbms/src/database/migration/):snapshots: drift hash viaxxh3(xxhash-rust), seeded with
TableSchemaSnapshot::latest_version().compute_driftcompares
persisted snapshots (loaded throughSchemaRegistry::stored_snapshots)
withS::compiled_snapshots()reachable through the boxed schema.diff: pure stored-vs-compiled diff producingVec<MigrationOp>.
Renames resolved via the newDatabaseSchema::renamed_from_dyn
dispatch, type changes routed through the widening whitelist or
MigrationOp::TransformColumn.plan: deterministic op ordering plus policy-driven validation
(destructive-op gate, defense-in-depth missing-default check).apply: journaled execution of structural ops (CreateTable,
DropTable,AlterColumn,AddIndex,DropIndex); tightening
validation (nullable: false,unique: true) scans existing rows
through schema dispatch. Column-mutating ops (AddColumn,
DropColumn,RenameColumn,WidenColumn,TransformColumn) return
the newMigrationError::DataRewriteUnsupporteduntil the
snapshot-driven (de)serializer (issue #91) lands.DropTableleaks
pages (issue #90).
Database wiring:
DbmsContextgainsCell<Option<bool>> drift(lazy cache) and
Cell<bool> migrating(apply-in-progress guard so internal reads
bypass the gate).WasmDbmsDatabase::ensure_no_driftis called as the first line of
everyDatabasemethod exceptrollback. ACL methods on
DbmsContextcontinue to bypass.Databasetrait gainshas_drift,pending_migrations(renamed
from the previousplan_migration), andmigrate(policy). The IC
adapter and any otherDatabaseimplementor must now implement them;
the test mock inwasm-dbms-apiis updated.
API additions (
wasm-dbms-api):fingerprint_for_name(&str) -> u64(xxh3_64), so the engine can
derive a registry key for tables it knows only by name.MigrationError::DataRewriteUnsupported { op }.xxhash-rustworkspace dependency.
Memory layer (
wasm-dbms-memory):SchemaRegistry::{stored_snapshots, register_table_from_snapshot, unregister_table, table_registry_page_by_name}.IndexLedger::init_from_keysfor snapshot-keyed init paths.test_utils::write_dummy_schema_snapshotso the table-registry unit
tests (which allocate raw pages and callTableRegistry::load) can
satisfy the snapshot-ledger decode that landed in #34's prior commit.
Macro additions (
wasm-dbms-macros):- Emit
compiled_snapshots_dyn,migrate_default_dyn,
migrate_transform_dyn, andrenamed_from_dynas object-safe
siblings of the existingSizeddispatch methods.
Benches (
ic-dbms-canister):- Replace hand-written
DatabaseSchemaimpls ineager_relationand
read_tablewith#[derive(DatabaseSchema)]. ~330 LOC of boilerplate
removed; the derive macro covers the same dispatch.
- migrations: IC layer endpoints for schema migrations
Wires the migration surface through the IC layer:
has_driftand
pending_migrationsas queries,migrateas an update, all admin-gated
via the existing ACL check. Adds matchingClienttrait methods with
implementations forIcDbmsCanisterClient,IcDbmsAgentClient, and
IcDbmsPocketIcClient, plus wrapper-canister bindings and PocketIC
coverage exercising both the direct client and wrapper paths on a
fresh canister (no drift, empty plan, migrate is a no-op). - migrations: WIT surface and IC migration docs
Add has-drift / pending-migrations / migrate to wit/dbms.wit plus the
supporting snapshot, op, and policy records. Wire them through the
example guest and host so the round-trip is exercised end-to-end.Document the IC migration flow: new docs/ic/guides/migrations.md, full
Candid signatures in docs/ic/reference/schema.md, and a Schema
Migrations section in docs/ic/guides/client-api.md. - migrations: snapshot-driven record codec for column-mutating ops
- memory: page reclamation via unclaimed-pages ledger (closes #90)
Reserve page 2 for an LIFO ledger of pages released by destructive ops.
RenameMemoryAccess::allocate_pagetoclaim_pageand addunclaim_page,
both built on newgrow_one_page/zero_pageprimitives.claim_page
pops the ledger before bumping the high-water mark;unclaim_pagezeros
the page and pushes it. JournaledWriter records the full pre-zero page so
rollback restores ledger state and c...
wasm-dbms 0.8.2
0.8.2
Released on 2026-04-21
Changed
- derive
Defaulton generated*UpdateRequeststructsAll fields on update requests are
Option<T>, soDefaultis always
derivable. This enables the..Default::default()struct-update pattern
when constructing partial updates, removing the need to writeNone
for every untouched field.
wasm-dbms 0.8.1
0.8.1
Released on 2026-04-05
Added
- add select_join to Database trait and rename CandidColumnDef to JoinColumnDef
Move select_join from a #[doc(hidden)] method on WasmDbmsDatabase to a
proper public method on the Database trait, making it the official API
for join queries. Rename CandidColumnDef to JoinColumnDef to better
reflect its purpose as the column definition type that carries table
provenance for join results. Update all docs to reference select_join
instead of select_raw for join queries.
Fixed
- apply LIMIT and OFFSET after ORDER BY to match SQL semantics
LIMIT and OFFSET were applied during the table scan (before sorting),
so ORDER BY + LIMIT didn't produce correct "top N sorted" results.
Now, when ORDER BY is present, LIMIT and OFFSET are deferred to after
sorting, matching standard SQL evaluation order. The early-exit
optimization is preserved when no ORDER BY is specified. - align insert offset to RawRecord alignment for fixed-size records
The second insert into a table with all fixed-size columns (e.g. Uint64 +
Uint64 + 1-byte CustomDataType) failed with OffsetNotAligned because:- table_registry::insert aligned the write offset using E::ALIGNMENT
instead of RawRecord::ALIGNMENT (which includes the 2-byte header). - page_ledger::commit double-wrapped the type in RawRecord, computing
RawRecord<RawRecord>::ALIGNMENT instead of RawRecord::ALIGNMENT,
causing incorrect free-space tracking.
- table_registry::insert aligned the write offset using E::ALIGNMENT
wasm-dbms 0.8.0
0.8.0
Released on 2026-04-05
Added
- add select_join to Database trait and rename CandidColumnDef to JoinColumnDef
Move select_join from a #[doc(hidden)] method on WasmDbmsDatabase to a
proper public method on the Database trait, making it the official API
for join queries. Rename CandidColumnDef to JoinColumnDef to better
reflect its purpose as the column definition type that carries table
provenance for join results. Update all docs to reference select_join
instead of select_raw for join queries.
Fixed
- apply LIMIT and OFFSET after ORDER BY to match SQL semantics
LIMIT and OFFSET were applied during the table scan (before sorting),
so ORDER BY + LIMIT didn't produce correct "top N sorted" results.
Now, when ORDER BY is present, LIMIT and OFFSET are deferred to after
sorting, matching standard SQL evaluation order. The early-exit
optimization is preserved when no ORDER BY is specified.
wasm-dbms 0.7.2
0.7.2
Released on 2026-04-02
Fixed
- export macros in wasm-dbms-api
wasm-dbms-macros were not actually exported as the documentation example were showing
wasm-dbms 0.7.1
0.7.1
Released on 2026-04-01
Documentation
- build docs from mdbook
Fixed
- rename generated loop variables in Table macro to avoid shadowing user field names
Fields named
valuecaused compile errors because the generated code
usedvalueas both the loop binding and destructure binding, shadowing
the field accumulator variable.
Miscellaneous
- derive CustomDataType on principal
wasm-dbms 0.7.0
0.7.0
Released on 2026-03-30
⚠ Breaking Changes
- change
MemoryProvider::readandMemoryAccess::read_atto take&mut selfMemoryProvider::read signature changed from &self to &mut self.
Added
- bench: add benchmark comparison crate against other in-memory DBMS
Add wasm-dbms-bench crate with Criterion benchmarks comparing wasm-dbms
against SQLite (in-memory) and DuckDB (in-memory) across CRUD operations,
bulk inserts, queries (filter, order, join), and transactions.Includes CI workflow for running benchmarks and uploading artifacts.
- B+ tree indexes for accelerated queries
Add a complete B+ tree index system to wasm-dbms. Every table
automatically gets an index on its primary key, and users can declare
additional single-column or composite indexes with the#[index]
attribute.Key changes:
Memory layer (wasm-dbms-memory):
- IndexLedger: per-table registry mapping column sets to B-tree roots
- IndexTree: page-per-node B+ tree with variable-size keys, doubly-linked
leaves for range scans, and automatic node splitting/merging - RecordAddress: lightweight (page, offset) pointer stored in leaf entries
- SchemaRegistry/TableRegistryPage extended with index_registry_page
- TableRegistry now owns and exposes an IndexLedger
- INSERT/UPDATE/DELETE maintain all indexes eagerly
DBMS layer (wasm-dbms):
- FilterAnalyzer: extracts index plans (Eq, Range, In) from query filters
- IndexReader: unified view merging base B-tree results with transaction
overlay additions/removals - IndexOverlay: in-memory BTreeMap tracking uncommitted index changes per
transaction, flushed on commit, discarded on rollback - SELECT, UPDATE, DELETE, and JOIN queries use indexes when a suitable
plan is found; remaining filter conditions applied as residual checks
Macro layer (wasm-dbms-macros):
#[index]attribute on fields for single-column indexes#[index(group = "name")]for composite indexes- Automatic primary key index generation in TableSchema
- Deduplicated shared macro logic from ic-dbms-macros into wasm-dbms-macros
Also includes CI improvements, dependency updates, and documentation
updates covering the index memory layout, query optimization, and
architecture changes. - add wasi-dbms-memory crate with file-backed MemoryProvider
Implements WasiMemoryProvider backed by a single flat file,
enabling wasm-dbms to persist data on any WASI-compliant runtime
(Wasmer, Wasmtime, WasmEdge). The file layout is byte-for-byte
equivalent to IC stable memory. - add #[unique] attribute for table fields
Add support for the #[unique] field attribute that enforces uniqueness
constraints on non-primary-key columns. A unique field automatically
gets a B+ tree index for efficient O(log n) duplicate detection.- Parse #[unique] in Table derive macro, set ColumnDef::unique and
auto-generate an index for the field - Add UniqueConstraintViolation error variant to QueryError
- Enforce uniqueness in InsertIntegrityValidator and
UpdateIntegrityValidator (update allows keeping own value) - Add comprehensive tests for insert, update, and transaction scenarios
- Update schema, errors, and IC reference documentation
- Parse #[unique] in Table derive macro, set ColumnDef::unique and
- add #[autoincrement] attribute for table fields
Add support for autoincrement columns in table schemas. Fields annotated
with#[autoincrement]automatically generate sequential values on
insert, starting from zero and incrementing by one.Implementation across all layers:
Memory layer (wasm-dbms-memory):
- AutoincrementLedger: per-table ledger storing current counter values
for each autoincrement column, persisted to a dedicated memory page - AutoincrementRegistry: HashMap-based registry mapping column names to
their current Value, with custom Encode implementation - SchemaRegistry: conditionally allocates an autoincrement page when a
table has autoincrement columns (Option in TableRegistryPage) - TableRegistry: integrates AutoincrementLedger as an optional field,
exposes autoincrement_next() to get the next value for a column
API layer (wasm-dbms-api):
- ColumnDef: add auto_increment field to column definitions
- MemoryError::AutoincrementOverflow: new error variant returned when
a column reaches its type's maximum value (uses checked_add) - Filter: support autoincrement columns in query filters
Macro layer (wasm-dbms-macros):
- Table derive macro: parse #[autoincrement] attribute on fields,
propagate auto_increment flag to generated TableSchema impl
DBMS layer (wasm-dbms):
- Database: wire autoincrement through insert operations
- Transaction overlay: support autoincrement in transactional context
Supported types: Int8, Int16, Int32, Int64, Uint8, Uint16, Uint32,
Uint64. Overflow returns AutoincrementOverflow error to prevent
duplicate key generation. - AutoincrementLedger: per-table ledger storing current counter values
CI
- run workflow only once in pr (branches
main) - run ci workflow against
x.y.zbranches - install nightly and check format before installing stable toolchain
- install ic-wasm with curl
Changed
- remove duplicated macros from ic-dbms-macros
Remove Encode, Table, CustomDataType, and DatabaseSchema derive macros
from ic-dbms-macros, keeping only DbmsCanister. These macros were
duplicated from wasm-dbms-macros with the only differences being crate
path prefixes and Candid/Serde derives on generated types.IC crates now re-export the wasm-dbms-macros versions through their
preludes. To support the IC requirement of Candid-serializable generated
types, a #[candid] attribute is added to wasm-dbms-macros' Table derive:
when present, generated Record, InsertRequest, and UpdateRequest types
derive CandidType, Serialize, and Deserialize. - 💥 change
MemoryProvider::readandMemoryAccess::read_atto take&mut selfFile-backed providers need mutable access to seek before reading.
Previously this was worked around with try_clone() on every read.
Making the trait honest about mutation removes that overhead and
simplifies implementations.
Documentation
- add WASI documentation
- update project description to better match the project identity
Fixed
- prevent PK from being indexed twice
using
#[index]on the primary key lead to duplicated index for the primary key - track PK changes in overlay patch_row to chain subsequent operations
- add missing Int8, Int16, Uint8, Uint16 variants to DataTypeKind and CandidDataTypeKind
Value enum already had these variants but DataTypeKind did not,
causing compile errors when using 8-bit or 16-bit integer types
in table field definitions via the derive macro. - autoincrement macro codegen and DBMS integration
Fix InsertRequest codegen for autoincrement fields:
- from_values: wraps found values in Autoincrement::Value, absent ones
in Autoincrement::Auto - into_values: skips Autoincrement::Auto fields, includes Value fields
- into_record: unwraps Autoincrement::Value to inner type for schema
Fix insert_contract test helper using wrong column index (order vs
user_id). Add full coverage tests for autoincrement at the DBMS layer:
sequential generation, explicit override, no recycle after delete,
transaction commit/rollback counter behavior, from_values/into_values
variants, and filter on autoincrement column.Wire autoincrement_next into TableRegistry as a public method.
- from_values: wraps found values in Autoincrement::Value, absent ones
Miscellaneous
- remove repeated compare benchmarks
- add Rust logo to crates.io badges in all READMEs
- removed kofi badge
- ignore
.DS_Store
Build
- update dependencies
wasm-dbms 0.6.0
0.6.0
Released on 2026-03-02
⚠ Breaking Changes
- migrate Principal from built-in to CustomDataType
Value::Principal and DataTypeKind::Principal removed.
Principal fields in tables must now use #[custom_type] annotation.
Existing stable memory schemas are incompatible (fingerprint change). - restructure workspace into wasm-dbms and ic-dbms layers
restructure workspace into wasm-dbms and ic-dbms layers
Added
- ic-dbms-api: add CustomValue struct with comparison and hashing
- ic-dbms-api: add CustomDataType trait
- ic-dbms-api: add Value::Custom variant and accessors
- ic-dbms-api: add DataTypeKind::Custom variant and CandidDataTypeKind
Add Custom(&'static str) variant to DataTypeKind for user-defined types.
Remove CandidType/Serialize/Deserialize derives from DataTypeKind since
it no longer needs to cross API boundaries directly. Introduce
CandidDataTypeKind as the Candid-serializable mirror with Custom(String)
for the canister API layer. Update CandidColumnDef to use the new type. - ic-dbms-macros: add #[derive(CustomDataType)] macro
Add a proc-macro derive that generates
impl CustomDataType(with
TYPE_TAG constant) andimpl From<T> for Valuefor user-defined types.
The attribute#[type_tag = "..."]is required and uses the same
NameValue parsing pattern as the existing#[table = "..."]attribute. - ic-dbms-macros: add #[custom_type] support to Table derive macro
When a field is annotated with #[custom_type], the generated code uses
Value::Custom(CustomValue { ... }) instead of Value::FieldType(field)
for to_values/from_values in TableSchema, Record, InsertRequest, and
UpdateRequest. This allows user-defined types implementing CustomDataType
to be used as table columns. - 💥 migrate Principal from built-in to CustomDataType
- add WIT interface definition for wasm-dbms Component Model API
- add WIT guest crate with FileMemoryProvider and example schemas
Create the wasm-dbms-example-guest crate scaffolding with:
- FileMemoryProvider: file-backed MemoryProvider implementation with
> persistence across process restarts and full test coverage - Example table schemas (User, Post) with ExampleDatabaseSchema
> implementing the generic DatabaseSchema trait - register_tables helper for DBMS context initialization
Fix wasm-dbms-macros to use DbmsError/DbmsResult instead of
IcDbmsError/IcDbmsResult and remove IC-specific candid/serde derives
from generated insert, update, and record structs, making the
generic macro layer truly runtime-agnostic. - FileMemoryProvider: file-backed MemoryProvider implementation with
- implement WIT guest bridge layer for Component Model exports
- add Wasmtime host binary for WIT Component Model example
Create the host-side binary that loads the guest WASM component via
Wasmtime, provides WASI filesystem access, and exercises every exported
database operation: insert, select, transactional commit, and rollback. - add wasm-dbms dependency to ic-dbms-canister
- add #[derive(DatabaseSchema)] macro for automatic schema dispatch
Add a DatabaseSchema derive macro that auto-generates the
DatabaseSchema trait implementation from a #[tables(...)] attribute,
eliminating ~130+ lines of boilerplate per schema. Two variants exist:
a generic one in wasm-dbms-macros and an IC-specific one in
ic-dbms-macros with IC crate paths. Update examples, tests, and docs. - add AccessControl trait with associated Id type for runtime-agnostic ACL
Introduce the AccessControl trait in wasm-dbms-memory to abstract access
control behind a generic interface. Different runtimes can use different
identity types: Vec (AccessControlList), Principal (IcAccessControlList),
or () (NoAccessControl). The A: AccessControl generic parameter is propagated
through DbmsContext, WasmDbmsDatabase, DatabaseSchema, integrity validators,
join engine, and both derive macros. Default type parameters preserve backward
compatibility. - add journaling-based atomicity to MemoryManager
Replace panic-based rollback in atomic() with a write-ahead journal in
MemoryManager. All writes via write_at and zero are recorded when a
journal is active, enabling byte-level rollback on error. This makes
atomicity runtime-agnostic, removing the dependency on IC's
trap-reverts-stable-memory semantics.Key changes:
- Add JournalEntry, begin/commit/rollback_journal to MemoryManager
- Refactor atomic() to use journal with nested-call awareness
- Refactor commit() to use a single journal spanning all operations
- Fix self vs db inconsistency in delete closure
- Fix pre-existing clippy is_multiple_of lint
- Add 14 journal unit tests and 1 commit-rollback integration test
- Add docs/technical/atomicity.md
Changed
- 💥 restructure workspace into wasm-dbms and ic-dbms layers
Split the monolithic ic-dbms crates into a two-layer architecture:
- wasm-dbms (generic layer): runtime-agnostic DBMS engine (wasm-dbms-api,
> wasm-dbms-memory, wasm-dbms, wasm-dbms-macros) - ic-dbms (IC layer): thin adapter for Internet Computer canister
> integration (ic-dbms-api, ic-dbms-canister, ic-dbms-macros,
> ic-dbms-client, example, integration-tests)
Also fixes integration test wasm paths to account for the new directory
depth and updates CI, docs, and build scripts accordingly. - wasm-dbms (generic layer): runtime-agnostic DBMS engine (wasm-dbms-api,
- consolidate IC thread-locals into DbmsContext
- remove duplicated IC database engine module
- update ic-dbms-canister prelude to re-export from wasm-dbms
- update IC API layer to use wasm-dbms database engine
- slim down DbmsCanister macro to IC API only
- update IC canister tests to use wasm-dbms engine
- update CHANGELOG, docs, and API for custom data types and AccessControl trait
Update CHANGELOG with custom data types, AccessControl, and DatabaseSchema entries.
Remove CallerContext in favor of AccessControl trait. Update IC macros to use
generic-layer AccessControl. Update example guest, Cargo.toml dependencies, and
documentation across wasm-dbms and ic-dbms crates. - remove IC-specific documentation from wasm-dbms crates
The generic wasm-dbms layer should not reference IC-specific concepts.
Remove all doc comments mentioning IC, canister, Principal, Candid,
IcDbmsError, and IcDbmsResult from the wasm-dbms crates. - make error types runtime-agnostic and replace ACL panic with error
Rename IC-specific error variants to runtime-agnostic names
(StableMemoryError → ProviderError, PrincipalError → IdentityDecodeError),
add ConstraintViolation variant, replace panic in ACL last-identity removal
with a proper error, simplify get_referenced_tables by removing thread-local
cache, and add DbmsContext threading documentation. - move journal from MemoryManager to transaction module
Extract the write-ahead journal from the memory layer into the DBMS
layer where it belongs as a transaction concern. Introduce MemoryAccess
trait so memory-crate functions are generic over the writer, allowing
JournaledWriter to intercept writes for rollback support.
Documentation
- add custom data types design document
Design for issue #35: type-erased CustomValue approach with
CustomDataType trait, no generic propagation through core API.
Principal becomes a CustomDataType impl in 0.6, prerequisite
for wasm-dbms extraction (#48) in 0.7. - update CHANGELOG for 0.6.0 custom data types
- add custom data types guide and update references
- New website for wasm-dbms
- add Wasmtime WIT Component Model example documentation
- update architecture docs after IC deduplication
Fixed
- move design doc to .claude/plans, add convention to CLAUDE.md
Design docs and plans belong in .claude/plans/ (gitignored),
not in docs/plans/. Added this convention to CLAUDE.md. - ic-dbms-macros: fix nullable custom type codegen using inner type
When a custom type field is declared as Nullable, the macro now
correctly uses the inner type T (not Nullable) for trait lookups
like CustomDataType::TYPE_TAG and Encode::decode in all codegen paths. - address code review findings
- Replace String::leak() with OnceLock-based static cache in
> Value::type_name() for Custom variants to prevent unbounded leaks - Add compile-time error when #[custom_type] and #[foreign_key] are
> combined on the same field
- Replace String::leak() with OnceLock-based static cache in
- harden custom data types and add CustomValue constructor
- Add cache size guard (max 64 entries) to Value::type_name() to
> prevent unbounded memory leaks on IC - Replace panicking .expect() with non-panicking if-let-Ok decode
> in macro codegen for custom types (record, insert, update) - Add CustomValue::new() constructor enforcing consistency between
> type_tag, encoded bytes, and display string - Add Project table with #[custom_type] owner field to example canister
- Add PocketIC integration tests for custom type CRUD and filtering
- Add cache size guard (max 64 entries) to Value::type_name() to
- exclude guest crate from native tests and fix clippy warning
The guest crate targets wasm32-wasip2 and cannot link on native targets.
Exclude it fromjust testusing --workspace --exclude. Also fix a
redundant_closure clippy warning in the host binary. - update MSRV to 1.91.1, fix ACL persist-before-panic, fix clippy warnings
- Set rust-version to 1.91.1 (actual MSRV per cargo msrv) across
> workspace Cargo.toml, CLAUDE.md, and all docs - Replace is_multiple_of (Rust 1.87+) with modulo check for MSRV compat
- Fix ACL remove_identity to check emptiness before persisting, preventing
> corrupted state on non-IC runtimes - Add #[allow(clippy::approx_constant)] to JSON test modu...
- Set rust-version to 1.91.1 (actual MSRV per cargo msrv) across
ic-dbms 0.5.0
0.5.0
Released on 2026-02-27
⚠ Breaking Changes
- Remove generic T from Query, since it's unnecessary
Remove
TfromQueryandQueryBuilder
Added
- 💥 Remove generic T from Query, since it's unnecessary
The
T: TableSchemaargument fromQueryandQueryBuilderwas actually unnecessary, because it didn't provide
any meaningful information. The T argument has just been moved to the dbmsselectmethod, in order to bring
information to the selected entity. - add generic select endpoint for untyped table queries (#10)
Add a
select_rawmethod to the Database trait and aselectcanister
endpoint that returnsVec<Vec<(CandidColumnDef, Value)>>, enabling
table queries by name without compile-time type information. This lays
the groundwork for future SQL and JOIN support. - ic-dbms-client: add
select_rawmethod to allow selecting untyped columns - implement JOIN support (INNER, LEFT, RIGHT, FULL) (#47)
Add user-facing join guide content to the querying and relationships
docs, create a technical deep-dive for the join engine, and update the
architecture overview and index with join-related entries.
Add cross-table join queries with nested-loop join engine, qualified
column resolution, NULL padding for outer joins, and filter support
on joined rows. Joins are available through the untyped select_raw
path and the generated select canister endpoint.
Performance
- batch fetch foreign keys in eager relation loading (#41)
Replace per-record N+1 foreign key fetching with a batched approach
using Filter::In queries. Adds ForeignFetcher::fetch_batch trait method,
HashSet-based FK deduplication, benchmarks, and uses the existing
TableColumns type alias throughout.
ic-dbms 0.4.0
0.4.0
Released on 2026-02-06
- New features:
- Issue 13: Added JSON filtering capabilities for querying JSON columns.
JsonFilter::Containsfor PostgreSQL@>style structural containment checksJsonFilter::Extractfor extracting values at JSON paths with comparison operationsJsonFilter::HasKeyfor checking path existence in JSON structures- Path syntax supports dot notation with bracket array indices (e.g.,
user.items[0].name)
- Issue 22: Added
AgentClientfor the ic-dbms-canister to interact with
the IC from an IC Agent.
- Issue 13: Added JSON filtering capabilities for querying JSON columns.
- Performance improvements:
- Issue 11: Implemented in-place update instead of delete+insert strategy
(#37).- Records whose size is unchanged are now overwritten directly in stable memory, avoiding unnecessary reallocation.
- Records whose size changes still fall back to delete+reinsert.
- Added
UpdateIntegrityValidatorthat allows keeping the same primary key during updates. - Cascade primary key changes to referencing tables via
update_pk_referencing_updated_table. - Extracted shared validation logic into
integrity::commonmodule.
- Replaced the external
likecrate with a custom SQL LIKE pattern engine (#42).- The new iterative two-pointer algorithm runs in O(n*m) worst-case with O(1) space and zero heap allocation, replacing the previous recursive approach that had exponential worst-case complexity.
- Issue 11: Implemented in-place update instead of delete+insert strategy
- Bug fixes:
- Fixed an issue with the IcCanisterClient which called
updatewith the wrong amount of arguments. - Fixed multi-column
order_byapplying sorts in the wrong order, causing only the last column's sort to survive
(#39).
- Fixed an issue with the IcCanisterClient which called
- Refactoring:
- Moved workspace crates into
crates/directory for better project organization
(#38). - Cleaned up
dbms.rswith extracted helpers, immutable borrow fixes, and moved tests to a separate file
(#40). - Reorganized and expanded project documentation (#31).
- Increased test coverage for ic-dbms-api, ic-dbms-canister, and ic-dbms-client.
- Moved workspace crates into
- Dependencies:
- Issue 12: Bump pocket-ic to 12.0.0.