Skip to content

datom

0.2.0Package record

A Unified Framework for Versioned, Traceable Tabular Data

0packages depend
706downloads / year
60.3%test coverage
13/13flavors OK

Overview

About

Provides versioned storage for tabular data without a database or a server. Each table is written as an immutable, content-addressed version -- identical content is detected and stored only once -- while its version history and metadata are kept as code in a 'git' repository and the data itself in a local filesystem or cloud object storage ('S3'). Any past version can be read back exactly by its identifier, and each table records the sources it was derived from, so a project carries full data lineage. A lightweight reader role retrieves current or historical data from storage alone, without 'git' or write access, giving downstream analyses and pipelines a single versioned source of truth. It targets analytical and scientific data management, such as preparing clinical study datasets, and is designed as a foundation for higher-level governance tooling.

Changes in 0.2.0

This release adds a second kind of artifact -- a **set**, which is a citable list

of exact data versions -- and renames one key in the manifest to make room for it.

The rename is the only breaking change, and what it breaks is *discovery*, not

access. Read the first two sections before upgrading a shared repo.

See vignette("citable-sets") for what sets are for and how to build one.

Before you upgrade: the manifest's artifact list is renamed **[breaking]**

.metadata/manifest.json and .datom/manifest.json now list artifacts under

**artifacts** rather than tables, and every entry carries a kind.

  • **Existing repos keep working, and there is no manual migration.** A manifest written before this change carries no format number; datom reads that as version 1 and converts it. A read converts in memory and leaves the file alone, so a reader with storage access and no clone is never stuck. A write converts the file and records the format it reached, so a repo is never half in one shape and half in the other.
Show all changes in 0.2.0Hide the rest of the changes in 0.2.0
  • **Upgrade everyone who shares a repo before anyone writes to it.** The compatibility above runs one way. After a single write from this version an older datom looks for the artifact list under a key that is no longer there, so datom_list() returns an empty frame and datom_summary() and datom_status() report zero -- **without an error**. datom_read() is unaffected: the data path never reads the manifest, so a collaborator who knows a table name and version can still read it. What they lose is the ability to see what the repo holds.
  • A write that converts a repo now says so and names that consequence. datom_validate(fix = TRUE) converts the copy in storage too, which is worth knowing because it reads as a repair rather than as a format change.
  • datom_list() gains a kind column, and its empty result gains current_data_sha (and version_count with include_versions = TRUE), so rbind() of two listings no longer fails when one is empty. datom_summary() gains set_count. datom_status()'s table count now counts tables rather than every artifact.
  • Three return-value fields still named tables are **unchanged**: datom_status()$tables, datom_validate()$tables, and the per-table results from datom_sync(). Only the manifest key moved.

Before you upgrade: a write is refused when this build cannot account for the repo

Every manifest and every per-artifact metadata document now declares a

schema_version. Stamping it mints no new version for anything.

A write stops **at the door** -- before any hashing, any local file write and any

commit, so a refusal leaves nothing half-written -- when this build meets a repo

it cannot fully account for: the repo declares a minimum datom version above this

one, the manifest declares a format this build does not know, or any document

carries a top-level field this build cannot classify.

  • **Reads and writes respond differently to the same evidence, on purpose.** A reader that meets a manifest it cannot use warns once and rebuilds the listing from storage rather than reporting an empty repo. A writer in the same position refuses. A reader that limps still answers the question it was asked; a writer that limps produces a file nobody agreed on.
  • A too-new **per-artifact** document is refused at any role, because nothing can rebuild it.
  • **All of this binds 0.1.1 and later.** 0.1.0 has no schema check, no field check and no version floor, and none can be added to a build that has shipped. If a 0.1.0 writer exists in your group, upgrading it is the only remedy.
  • A field this build does not recognise is **preserved** rather than deleted, in per-artifact metadata, manifest entries, the manifest top level and version-history entries. So a document written by a newer datom survives a round trip through an older one.
  • project.yaml now declares its own format number, separate from the repo's, so a manifest format bump can never refuse a config whose shape never changed. An unrecognised key in that file is still tolerated.

New: citable sets

A **set** is a named, versioned list of pointers at exact versions of other

artifacts, plus free-text labels. It stores no data of its own, and reading one

needs access to the set's own project only -- so a fifty-table product can be

citable by someone entitled to none of the tables. vignette("citable-sets")

walks the whole arc.

  • **datom_write_set()** writes one. It needs a repo that declares mode: product and names its set in .datom/project.yaml; one repo owns one set. Re-writing identical content is a no-op: no commit, no version, no upload.
  • **datom_get_set()** reads one back and returns references, not data, which is why the verb is get. Every member carries a $fetch(conn) link that pins the version it was read at -- a citation, not a subscription. A member that is itself a set comes back as a pointer, so read cost does not grow with depth.
  • **datom_member()** declares one member. **datom_assemble_set()** starts an empty set and **datom_add_member()** adds one member at a time, to a new set or one read back, so a bad version is reported on the line that added it. A set in memory holds no connection: pass conn = to add a member by name, and write with datom_write_set(conn, x) or x |> datom_write_set(conn = conn).
  • **On a product repo, datom_sync_manifest(conn, sources = ) and datom_sync(conn, manifest, sources = ) build and refresh the set** the way they onboard files elsewhere: map what the source projects hold, review it as a data frame, apply it. Tables and sets in a source are handled alike. The preview never proposes a removal and says which members it could not check. Unlike table sync, applying writes nothing: datom_write_set() saves the set. See ?datom_sync_manifest and ?datom_sync.
  • **datom_parent(conn, table, x = )** takes the parent's version from the set you hold, resolving the name as datom_fetch_member() does, and returns a list ready for datom_write(parents = ). Calls with version = are unchanged.
  • **datom_fetch_member()**, **datom_list_members()** and **datom_structure_members()** get at members: the data, a row per member per label, or a view grouped by label. Labels are the navigation axis -- a name is not a unique key, since one table at two versions is a legal pair.
  • **datom_update_members()** and **datom_remove_members()** edit a set that already exists. Neither writes anything: they hand the edited set back and the write is yours. Repointing reports what moved before you write it, keeps each member's labels, and mints no version when nothing has moved. Edits made together produce one commit message naming all of them.
  • A mode: product repo can commit your own code and renv.lock in the **same commit** as the set, with datom_write_set(include_paths = ), so checking out a set version gives you the data pointers plus what produced them. A product repo refuses to onboard files -- it builds its artifacts rather than importing them.
  • datom_write_set() stops before writing anything when a member's recorded parents name an input that the set pins at a different version (the output was not derived again after its inputs moved), and when the set you pass belongs to another repo, by name or by project. See ?datom_write_set.
  • datom_validate() understands both kinds. A set is checked for members whose pinned versions still exist and for a recorded payload hash, without descending into members that are themselves sets. fix = TRUE can restore a set's payload from git when storage has lost it.
  • Per-artifact metadata now records kind, which is part of a version's identity, so a table and a set can never share a version string. **Every existing table mints one extra version at its next write** because of it; the stored data is not re-uploaded, since the content hash does not move.

New: committing your own content through datom

**datom_repo_commit()** and **datom_repo_push()** let a downstream package put

its code, lockfile or build state into the data repo without importing git2r.

paths = NULL means what git add . means, which is the **opposite** of what

datom's own writes do -- and that is the point: datom's own commits fire when

datom chose and must never sweep up work in progress, while these fire because

you asked. Commit is idempotent, push is convergent, and a no-op still pushes when

the branch is ahead. See ?datom_repo_commit for what it will and will not sweep

in.

Every version now records the commit that produced it

datom_history() gains a commit_sha column.

The value is worked out by datom, never supplied: from the commit it just made,

or recomputed from git history for a version that has none. Only the copy in

storage carries it -- your clone's copy is committed *inside* the commit that

would name it -- which is right, since the field exists for the reader who has no

clone.

**A version means content, not code**, and this is the part most likely to look

like a bug. Refactor a build script, re-run it, get identical data: no new version

is minted, and the recorded commit still points at an earlier one that does not

contain the code you are looking at. It names a commit that provably produces that

version, not every commit that could.

Smaller changes

  • Every artifact's metadata records a **project** field: the name the writing repo declares in its own config, not the label on your connection. Two people can label the same repo differently, and a citation has to mean one thing. No existing artifact gains a version for it.
  • A table's metadata **no longer records column_hashes**, the per-column digests added in 0.1.1. A per-column digest lets anyone who can read the metadata confirm a guess about a column's values. Nothing needs doing and no version moves; existing files lose the field the next time their table is written. See "What metadata reveals about your data" in vignette("design-version-shas") (#119).
  • datom_example_data("vs") returns a vital-signs table for the same 48 subjects and visits as lb. The other four example tables are unchanged.
  • New **datom_storage_read_json()** on the storage extension API, for reading a JSON document out of a project's namespace by relative key.
  • A repo whose manifest cannot be read is listed by rebuilding the index from storage, with one warning naming the upgrade, rather than reported as empty.
  • Identity hashing now selects fields by an explicit list rather than by exclusion, so a field this build has never heard of no longer folds into the hash and reports a change on content that did not move. Every existing hash is unchanged (#100).
  • .datom_check_git_current() no longer compares against stale refs after a failed fetch (#104).

From NEWS.md in the release

Install

Health

CRAN checks
13OK
Slowest check: 13.3 min · r-oldrel-windows-x86_64
Status changes
  • OK13 OK2026-09-13
  • ERROR8 OK, 2 ERROR2026-09-04
  • OK7 OK2026-09-02
Advisories

none known

Documentation

In release 0.2.0
READMEYes · 1,331 wordsVignettesYes · 7 · dynamicNEWSYes · 100% structured · mentions 0.2.0Citation fileNoWebsiteYes · pkgdown
Help pages
306 (247 internal)includes a package overview page
Examples that run
100%58 run in a plain check (35 of them under a condition)
Exported functions with examples
100%
Documented parameters
100%
Return-value docs
100%
Help pages citing references
0%

Downloads

706
CRAN downloads in the past year
Rank #18,007 · ~2/day · ~59/mo
Daily download trend is not available in this view yet.
42230 days
70690 days
7061 year
Compare downloads with other packages →
Also on13 r2u13 autocran

Repository

1Stars
0Forks
21Open issues
0Open PRs
3Releases
511Commits
2Commit identities
511 commits · Last activity 2026-10-03 · 0% stars, 30d
Responsiveness
How these are sampled
PRs merged (all time)
99%
Median days to close, 50 most recently updated closed issues
12
Median days to close, 50 most recently updated closed PRs
0

Stars over time

2026-09-02 · 02026-09-03 · 1
PracticesBeta

14 development-tooling and community-health practices detected across 6 families in the upstream repository

Checks run against github.com/amashadihossein/datom on 2026-10-11.

Continuous integration (2)
GitHub ActionsR CMD check workflow

The R CMD check workflow runs on Linux, macOS and Windows, and on R-devel

Governance and community (5)
Code of conductContributing guideIssue templatesPR templateSecurity policy
Docs source (4)
README.Rmdpkgdown

GitHub Pages site last deployed 2026-10-03 · The repository has a site deploy workflow

pkgdown site last built 2026-10-03

Coverage (1)
Coverage reporting
Show all practicesHide 2 practices
Reproducibility and dev environment (1)
data-raw/
CRAN release process (1)
cran-comments.md
How this is detected·Detection ruleset v3 (2026-09-26)
AI coding toolsBeta

This repository shows signs of AI coding tools.

  • GitHub Copilotfirst seen 2026-02-08
    Seen in the repository: .github/copilot-instructions.md
  • Kiro, Amazon Q's successorfirst seen 2026-06-14
    Seen in the repository: .kiro
    Named in .Rbuildignore: .kiro
  • Claude Codefirst seen 2026-07-26
    Pull request it wrote: opened by a project member
How this is detected·Detection ruleset v4 (updated 2026-09-27)

Dependencies

Declared dependencies
19 external dependencies (excludes base and recommended)

Installing datom adds 29 packages (22 with compiled code, 16 MB of source tarballs). Heaviest: arrow 4.2 MB, Rcpp 1.8 MB, fs 1.4 MB.

Depends (1)
R >= 4.1.0
LinkingTo (0)
none
Enhances (0)
none
Reverse dependencies
0direct
0indirect

Nothing depends on this yet.

Datasets

People & History

People (1)
Author, Maintainer since 0.1.1 (2026), Copyright holder
Releases (3)

Pick two releases to compare their code metrics.

  • 0.2.0Latest
    record
    2026-10-03 · current release · diff ↗ ·
    added 13 exports
    datom_add_member, datom_assemble_set, datom_fetch_member, datom_get_set, datom_list_members, datom_member, datom_remove_members, datom_repo_commit, datom_repo_push, datom_storage_read_json, datom_structure_members, datom_update_members, datom_write_set
  • 0.1.2
    record
    2026-09-08 · diff ↗
  • 0.1.1
    record
    2026-09-01
  • R
    R 4.6.0 released · 2026-04-24

Package metadata

First published
2026-09-01
Total releases
3 / 1 yrs
License
MIT + file LICENSE OSI
Minimum R
≥ 4.1.0
Download size
786 KB

Cite

Cite this package

Run in R for the authors' preferred citation:

citation("datom")
Mashadi-Hossein, A. (2026). datom: A Unified Framework for Versioned, Traceable Tabular Data (Version 0.2.0) [Computer software]. https://doi.org/10.32614/CRAN.package.datom

This package has no citation file, so citation() returns this entry built from DESCRIPTION.

Cite the R Observatory

For a number measured here: a download total, a coverage figure, an archival date.

APA

Balamuta, J. J. (2026). R Observatory: Metrics for datom version 0.2.0 [Data set]. HJJB, LLC. Data release v2026-10-18. https://doi.org/10.5281/zenodo.21843040

From data release v2026-10-18, which the citation names so these numbers can be found later. More on citing and the projects behind them.

Report a problem with this page →

Privacy choices

These apply to this browser and are stored on this device only. Nothing about your choice is sent to us.

Read the privacy policy