Blobs / Copies and expiry
Copies and expiry
A copy costs a row, whatever the file's size: stored bytes never change, so two files can share them. A rename is a copy and a delete in one write. A file can expire a span after it was written, and its bytes go once nothing names them.
await docs.copy('notes.md', 'notes (copy).md') // FileInfo; no bytes are copied
await docs.rename('draft.md', 'final.md') // ConflictError if final.md is thereawait docs.copy("notes.md", "notes (copy).md")
await docs.rename("draft.md", "final.md")_, err = docs.Copy(ctx, "notes.md", "notes (copy).md")
_, err = docs.Rename(ctx, "draft.md", "final.md")docs.copy("notes.md", "notes (copy).md")?;
docs.rename("draft.md", "final.md")?;Copies never replace by surprise
put and an upload are writes of a path and replace what it held. copy and
rename move a file that exists onto a path that may hold one, so a path
that holds a file is conflict, unless ifMatch names the version to
replace:
const final = await docs.head('final.md')
await docs.rename('draft.md', 'final.md', { ifMatch: final!.etag }) // replaces exactly that versionfinal = await docs.head("final.md")
await docs.rename("draft.md", "final.md", if_match=final.etag)final, found, err := docs.Head(ctx, "final.md")
_, err = docs.Rename(ctx, "draft.md", "final.md", blobs.IfMatch(final.ETag))let final_ = docs.head("final.md")?.expect("final.md");
docs.key("final.md").if_match(&final_.etag).rename_from("draft.md")?;| Call | Source missing | Target holds a file |
|---|---|---|
put, upload | — | replaced |
copy, rename | not found | conflict, unless ifMatch |
create | — | nothing written, false |
A copy and its source are two files from then on: replacing or deleting one
leaves the other, and a copy outlives its source (contract BLOB-05). Both
stay within one set of files; between two sets, read and put.
Expiry
const reports = store.files('reports', { ttl: '24h' })
await reports.put('report.csv', csv) // expires 24 hours from now
await reports.put('report.csv', csv, { ttl: '7d' }) // its own term
await reports.expire('report.csv', '1h') // from now; a Date for a timereports = store.files("reports", ttl="24h")
await reports.put("report.csv", csv)
await reports.put("report.csv", csv, ttl="7d")
await reports.expire("report.csv", "1h") # a datetime for a time- The set's
ttlis the term of every file written without its own, not a ceiling: a write that gives its own keeps it. - A term counts from the write, and every write gets its own: an export written again lives its day again.
- An expired file is gone for readers at once:
getandheadgive nothing. Its bytes are removed in the background, within a minute. expireson a file says when it goes.
A backup does not belong in files with a ttl.
Deleting
await docs.delete('notes.md') // nothing to delete is not an error
await docs.folder('users', 42).clear() // a folder, at once, however many filesawait docs.delete("notes.md")
await docs.folder("users", 42).clear()err = docs.Delete(ctx, "notes.md")
err = docs.Folder("users", 42).Clear(ctx)docs.delete("notes.md")?;
docs.folder("users").folder(42).clear()?;A delete, a clear, an expiry or a replace drops the file's name in one commit. The bytes stay as long as a copy or a reader that opened them still holds them, then go in the background.