Skip to contents

Moves members of a set forward to the versions that are current now, and returns the set with those pointers changed. Nothing is written: the report you see is the dry run, and the set is stored only when you pass the result to datom_write_set().

Usage

datom_update_members(
  x,
  conn,
  member = NULL,
  tags = NULL,
  version_from = NULL,
  version_to = NULL
)

Arguments

x

A datom_set, from datom_get_set() or datom_assemble_set().

conn

A datom_conn from datom_get_conn(), or a list of them – one per project the selected members belong to.

member

Optional: the member to repoint, as its name, a member record, or a link. NULL (the default) selects every member.

tags

Optional named list of labels narrowing the selection, e.g. list(type = "input"). A member matches when it carries every label listed.

version_from

Optional version, or a prefix of one, narrowing the selection to the member pinned at it.

version_to

Optional exact version to move to. NULL (the default) means whatever that artifact's project reports as current. Requires the selection to resolve to a single member.

Value

x with the matching members repointed, and what changed appended to its datom_edits attribute.

Details

This is the operation a product needs when its inputs move on – a hundred members of which thirty upstream tables have advanced. Doing it by hand is list surgery on what datom_get_set() returned, and two of the obvious spellings are silently wrong: filtering members by name drops every version of that name, and rebuilding a pointer from its name plus a new version drops that member's labels.

Which connection to pass

One per project the set spans, since access in datom is per project. A set whose members all live in the project that owns it needs only that one connection; a product drawing on three studies needs three, in a list.

A set's projects can be listed offline, with no connection at all:

Which members move

With no member, every member – refreshing everything is the common case and rerunning it changes nothing. Otherwise select one the way datom_fetch_member() does: by name, by a member record, or by a link. tags and version_from narrow either a name or the sweep, so tags = list(release = "live") repoints the labelled members and leaves the rest pinned.

A name that matches more than one member aborts, because the request cannot be honoured as typed; a sweep that meets the same pair skips it and says so, because refusing a whole refresh over one frozen baseline would make the first update on such a set an error.

Which version each member moves to

version_to omitted, each selected member moves to the version its own project reports as current, and every move is reported before anything is written. That is the one place datom infers "newest", and the reason it is allowed here is in the verb's name: a pointer constructor requires an explicit version (datom_member() refuses to guess), while a verb whose whole meaning is move this forward states the time-dependence up front and then says what it picked. What the set records is still an exact version, so a script that later reads that set is as reproducible as ever.

version_to supplied, the selected member moves to exactly that version – a rollback to a known-good, or a deliberate step to something that is not the newest. It requires the selection to resolve to one member, because one explicit version across several artifacts is not a meaning. It is also what makes this verb better than removing and re-adding a member: the labels come with it, where re-adding makes you retype them.

What it declines to do, and how

SituationResponse
a member's project has no supplied connectionthe whole call is refused, naming that project
a member's artifact no longer appears in its projectreported, and its pin is left alone
two members share a name and a projectboth skipped and reported

The first refuses because whether those members moved is unknowable, and reporting them as unchanged would state something nothing checked. The second does not, because the answer is known: the pinned version is immutable and still reads, so the set stays writable.

What comes back

The set it was handed, with matching members repointed and each moved member's labels byte-identical to what they were.

When something moved, a datom_set's version and data_sha are emptied: they described the payload it was read as, and that is no longer what the object holds. When nothing moved they are left alone, because the object still describes exactly that stored version.

The returned object also carries a log of what changed, which datom_write_set() uses for the commit message when you pass no message of your own – so git log names what moved instead of saying Update {name}. datom_remove_members() adds to the same log, so editing both ways before you write produces one message describing both. Passing x$members rather than x to the write loses that and nothing else.

See also

datom_remove_members() to drop members instead, datom_write_set() to store the result, datom_list_members() to see what a set holds, datom_member() to build a pointer from scratch.

Examples

# Offline, self-contained: a bare git repo stands in for GitHub and a
# local directory for object storage.
if (requireNamespace("git2r", quietly = TRUE)) {
  tmp <- tempfile("datom-example-")
  remote <- file.path(tmp, "remote.git")
  dir.create(remote, recursive = TRUE)
  git2r::init(remote, bare = TRUE)

  store <- datom_store(
    data = datom_store_local(file.path(tmp, "storage")),
    github_pat = "example-token", # role selector; a local remote needs none
    data_repo_url = remote,
    validate = FALSE
  )
  # A product repo declares itself as one and names the single set it owns.
  datom_init_repo(file.path(tmp, "repo"), "example_project", store,
                  mode = "product", set = "example_product")

  conn <- datom_get_conn(file.path(tmp, "repo"), store)

  dm <- datom_example_data("dm")
  datom_write(conn, data = dm, name = "dm")
  datom_write_set(conn, list(
    datom_member(conn, "dm", datom_history(conn, "dm")$version[1],
                 tags = list(type = "input"))
  ))

  # The table moves on, so the set now cites an older version of it.
  datom_write(conn, data = dm[-1, , drop = FALSE], name = "dm")

  x <- datom_get_set(conn, "example_product")
  x <- datom_update_members(x, conn)

  # The label came with it, and nothing is stored until the write.
  print(datom_list_members(x))
  datom_write_set(conn, x)

  unlink(tmp, recursive = TRUE)
}
#> ℹ Created store directory /tmp/Rtmpvh48Dj/datom-example-1a7632e063ed/storage.
#> ✔ Initialized datom repository "example_project" at /tmp/Rtmpvh48Dj/datom-example-1a7632e063ed/repo
#> ✔ Wrote "dm" (full): "b5cbba45"
#> ✔ Wrote set "example_product" (1 member): "5c776f28"
#> ✔ Wrote "dm" (full): "e4d6537b"
#> ✔ Repointed 1 member, of 1 selected.
#> project example_project:
#>   dm  b5cbba45 -> e4d6537b
#> ℹ Nothing has been written. Write the set with `datom_write_set(conn, x)`.
#>   name         project
#> 1   dm example_project
#>                                                            version  kind  key
#> 1 e4d6537b918c1b413865d50e7dd4745fd28012f3395ab507f79cb15b5eb0482a table type
#>   value
#> 1 input
#> ✔ Wrote set "example_product" (1 member): "06070474"