Skip to content
Merged
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
349 changes: 322 additions & 27 deletions packages/coln-js-runtime/src/rust/handles.rs

Large diffs are not rendered by default.

16 changes: 16 additions & 0 deletions packages/coln-js-runtime/src/ts/RealmBindings.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// SPDX-FileCopyrightText: 2026 Coln contributors
//
// SPDX-License-Identifier: Apache-2.0 OR MIT

import type { StoreHandle, TransactionHandle } from "#wasm-bodge/bindings"

export interface ColnSchema {
entities: readonly unknown[]
rules: readonly unknown[]
}

export interface RealmBindings<ViewRoot = unknown, TransactionRoot = unknown> {
schema: ColnSchema
View: new (store: StoreHandle) => { root: ViewRoot }
Transaction: new (store: StoreHandle, transaction: TransactionHandle) => { root: TransactionRoot }
}
2 changes: 2 additions & 0 deletions packages/coln-js-runtime/src/ts/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
export type { CommitChunk, RowRef, RowView, Value } from "#wasm-bodge/bindings";
export { CommitResult, StoreHandle, TransactionHandle, valueEqual } from "#wasm-bodge/bindings"

export type { RealmBindings, ColnSchema } from "./RealmBindings"

export * as ColnSet from "./ColnSet";

export * as ColnRef from "./ColnRef";
Expand Down
13 changes: 2 additions & 11 deletions packages/coln-js-runtime/tests/basic-ir/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,10 @@
//
// SPDX-License-Identifier: Apache-2.0 OR MIT

import { StoreHandle, type TransactionHandle } from "@coln-project/runtime";

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mvr Can I have your 👀 on this little change? It seems sensible to me, but I wonder if you have opinions on this.


interface RealmModule<ViewRoot, TransactionRoot> {
schema: unknown;
View: new (store: StoreHandle) => { root: ViewRoot };
Transaction: new (
store: StoreHandle,
transaction: TransactionHandle,
) => { root: TransactionRoot };
}
import { StoreHandle, type RealmBindings } from "@coln-project/runtime";

export function beginRealm<ViewRoot, TransactionRoot>(
realm: RealmModule<ViewRoot, TransactionRoot>,
realm: RealmBindings<ViewRoot, TransactionRoot>,
) {
let store = StoreHandle.fromTheory(JSON.stringify(realm.schema));
const transaction = store.beginTransaction();
Expand Down
6 changes: 6 additions & 0 deletions packages/coln-store/src/commit/chunk.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ impl From<ChunkType> for u8 {
}
}

/// A chunk what the external world sees as a "chunk" of data, right now it is
/// just a commit, but in the future it might be a sedimemtree fragment.
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum Chunk {
Commit { header: Header, payload: Vec<u8> },
Expand All @@ -53,6 +55,10 @@ impl Chunk {
Ok(chunk)
}

pub fn is_root(&self) -> bool {
self.chunk_type() == ChunkType::Root
}

pub(crate) fn chunk_type(&self) -> ChunkType {
match self {
Chunk::Commit { header, .. } | Chunk::Root { header, .. } => header.chunk_type,
Expand Down
2 changes: 2 additions & 0 deletions packages/coln-store/src/commit/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ pub enum CodecError {
IOError(io::Error),
SchemaError(String),
DataFormatError(String),
DataContentError(String),
ChecksumMismatch,
DecodeError(hexane::PackError),
ChunkMismatch { expected: ChunkType, got: ChunkType },
Expand All @@ -26,6 +27,7 @@ impl fmt::Display for CodecError {
CodecError::IOError(err) => write!(f, "io error: {err}"),
CodecError::SchemaError(msg) => write!(f, "schema error: {msg}"),
CodecError::DataFormatError(msg) => write!(f, "data format error: {msg}"),
CodecError::DataContentError(msg) => write!(f, "data content error: {msg}"),
CodecError::ChecksumMismatch => write!(f, "chunk checksum mismatch"),
CodecError::DecodeError(err) => write!(f, "decode error: {err:?}"),
CodecError::ChunkMismatch { expected, got } => write!(
Expand Down
54 changes: 12 additions & 42 deletions packages/coln-store/src/commit/pst.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
use std::io::Write;

use crate::commit::Commit;
use crate::commit::chunk::{Chunk, ChunkType};
use crate::commit::chunk::Chunk;
use crate::commit::error::CodecError;
use crate::commit::leb128 as commit_leb128;
use crate::store::Store;
Expand Down Expand Up @@ -38,7 +38,14 @@ pub fn encode_store(store: &Store) -> Result<Vec<u8>, CodecError> {
/// Decode a store from bytes produced by [`encode_store`].
pub fn decode_store(data: &[u8]) -> Result<Store, StoreError> {
let encoded = read_store_envelope(data)?;
decode_store_chunks(encoded.chunks)
let (store, pending) = Store::try_from_chunks(encoded.chunks)?;
if !pending.is_empty() {
return Err(CodecError::DataContentError(
"store snapshot contains commits that could not be applied".into(),
)
.into());
}
Ok(store)
}

struct EncodedStore {
Expand Down Expand Up @@ -83,43 +90,6 @@ fn write_commit_chunk(buf: &mut Vec<u8>, commit: &Commit<'_>) {
Chunk::from(commit).write(buf)
}

fn decode_store_chunks(chunks: Vec<Chunk>) -> Result<Store, StoreError> {
let roots = chunks
.iter()
.filter(|chunk| chunk.chunk_type() == ChunkType::Root)
.collect::<Vec<_>>();
if roots.is_empty() {
return Err(CodecError::DataFormatError("commit graph has no root commit".into()).into());
}
if roots.len() > 1 {
return Err(
CodecError::DataFormatError("commit graph has multiple root commits".into()).into(),
);
}

let root_commit = Commit::from_chunk((*roots[0]).clone(), |_| None)?;
let root_payload = root_commit.root_payload()?;
let mut store = Store::try_from_ir(root_payload)?;

let mut commits = Vec::new();
for chunk in chunks {
if chunk.chunk_type() == ChunkType::Root {
continue;
}

let commit = Commit::from_chunk(chunk, |path| {
store
.resolve_table(path)
.and_then(|oid| store.table_meta(oid))
})?;
commits.push(commit);
}

store.apply_commits(commits)?;

Ok(store)
}

#[cfg(test)]
mod tests {
use coln_flir_rs::ir::{BuiltinTy, ColType, ColumnEntry, EntityVariant};
Expand Down Expand Up @@ -209,13 +179,13 @@ mod tests {
.expect("encoded store contains a chunk magic")
}

fn is_missing_dep_error(result: Result<Store, StoreError>) -> bool {
fn is_data_content_error(result: Result<Store, StoreError>) -> bool {
matches!(
result,
Err(err)
if matches!(
&err,
StoreError::Commit(crate::store::error::CommitApplyError::MissingDep)
StoreError::Encode(CodecError::DataContentError(_))
)
)
}
Expand Down Expand Up @@ -352,7 +322,7 @@ mod tests {
frame_chunk(ChunkType::Commit, commit.payload()),
]);

assert!(is_missing_dep_error(decode_store(&bytes)));
assert!(is_data_content_error(decode_store(&bytes)));
}

#[test]
Expand Down
16 changes: 6 additions & 10 deletions packages/coln-store/src/store/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

use crate::commit::error::CodecError;
use crate::commit::graph::CommitGraphError;
use crate::commit::hash::CommitHash;
use crate::solver::compile::CompileError;
use crate::solver::validate::RuleViolation;
use crate::table::ValidationError;
Expand All @@ -27,15 +28,10 @@ pub enum StoreError {

#[derive(Debug, thiserror::Error)]
pub enum CommitApplyError {
#[error("missing commit dependency")]
MissingDep,
#[error("disconnected commit")]
DisconnectedCommit,
// A commit that should definitely exist but is missing
#[error("missing commit")]
MissingCommit,
#[error("A commit {0} with no dependency")]
DanglingCommit(CommitHash),
#[error("An existing commit has conflict payload")]
ConflictPayload,
#[error("Root commit cannot be applied")]
RootCommit,
ConflictPayload(CommitHash),
#[error("Root commit {0} cannot be applied")]
RootCommit(CommitHash),
}
Loading
Loading