Attachments¶
An attachment connects values to documents via keys. It is the fundamental mechanism for associating typed data with document instances: each attachment is, in effect, a typed map from a key to a document.
An attachment is declared on a pair of types — a concept (or club, or
ANY_CONCEPT) and a value type:
const att = defs.createAttachment(ns, 'A_I', conceptType, Type.INT64);
Keys are minted from the attachment and projected to match how the value is
filed: att.createKey().toParentKey() for the parent concept,
.toClubKey(club) for a club membership, and .toAnyConceptKey() for an
ANY_CONCEPT attachment.
When to use: reach for an attachment whenever you need to store and
retrieve values keyed by document. AttachmentGetting provides
read access (keys, get, has); AttachmentMutating is one —
it extends it, as in C++, so it is accepted wherever read access is required and
attachmentGetting() hands out the read-only view of the same attachments —
and adds the write operations (set, update, and the collection-field ops
unionInSet / subtractInSet, unionInMap / subtractInMap,
insertInXarray / updateInXarray / removeInXarray).
Quick Start¶
const {
CommitDatabase, CommitStateBuilder, CommitMutableState, Type,
} = require('@digitalsubstrate/dsviper');
const db = CommitDatabase.createInMemory();
db.extendDefinitions(defs.const());
// Write via AttachmentMutating
const mutableState = new CommitMutableState(CommitStateBuilder.initialState(db));
const mutating = mutableState.attachmentMutating();
mutating.set(att, key, 42); // INT64 document
db.commitMutations('Set A_I', mutableState);
// Read via AttachmentGetting, off the last commit
const state = CommitStateBuilder.state(db, db.lastCommitId());
const getting = state.attachmentGetting();
for (const k of getting.keys(att)) { // keys(att) is iterable
const doc = getting.get(att, k); // ValueOptional
console.log(doc.unwrap()); // INT64 unwraps to a bigint (42n)
}
db.close();
For a structured value type, build the document from the attachment itself:
const att_s = defs.createAttachment(ns, 'ac_S', Type.ANY_CONCEPT, structType);
mutating.set(att_s, key.toAnyConceptKey(), att_s.createStructure({ f_i: 42, f_s: 'a string' }));
Operations on a closed CommitDatabase, or a commit that violates an
attachment’s type constraints, throw a JS Error whose name is
'ViperError'.
See also: the Python reference, the database guide, and the commit API.
Generated from the @digitalsubstrate/dsviper TypeScript declarations (index.d.ts) by TypeDoc.
Core Classes¶
Class |
Description |
|---|---|
The declaration binding a concept to a value type |
Attachment Interfaces¶
Class |
Description |
|---|---|
Read access to the documents attached to a set of keys |
|
Expresses fine-grained mutations of the documents attached to keys |
Reference¶
- class Attachment()¶
The declaration binding a concept to a value type.
From it, keys are minted and documents created. It holds no document: a store does, and AttachmentGetting reads one by attachment and key.
Note: Not directly instantiable.
exported from
index.d- Attachment.createDocument()¶
Return a new document.
- Returns:
Value
- Attachment.createKey(instanceId)¶
- Return a key for this attachment, naming the instance instanceId, or a fresh
instance when it is undefined.
- Arguments:
instanceId (ValueUUId | null)
- Returns:
ValueKey
- Attachment.createStructure(initialValue)¶
Return a new document of this attachment’s document type.
initialValue fills it in; throw if it does not fit the type.
- Arguments:
initialValue (ValueStructure | { [fieldName: string]: InputValue; } | null)
- Returns:
ValueStructure
- Attachment.description(namespace)¶
Return the attachment rendered for display.
With namespace, every name is written relative to it. Without, the key and document types are written relative to the attachment’s own namespace, and the attachment’s name in full.
- Arguments:
namespace (NameSpace | null)
- Returns:
string
- Attachment.documentType()¶
Return the type of the document.
- Returns:
Type
- Attachment.documentation()¶
Return the documentation the attachment was created with, empty when none was given.
- Returns:
string
- Attachment.identifier()¶
Return the identifier, the key type and the name joined by a dot.
App::User.profile, for an attachment named profile on a concept User of namespace App. That is keyType().representation(); typeKey().representation() answers the same question with key<App::User>, which is not what goes here.
- Returns:
string
- Attachment.keyType()¶
Return the type of the key.
- Returns:
AbstractionType
- Attachment.keyTypeName()¶
Return the key’s TypeName.
- Returns:
TypeName
- Attachment.keysType()¶
Return the set<key> type a whole key listing has.
- Returns:
TypeSet
- Attachment.optionalDocumentType()¶
Return the type of the optional document.
- Returns:
TypeOptional
- Attachment.representation(namespace)¶
Return the declaration as text, qualified against namespace when one is given.
- Arguments:
namespace (NameSpace | null)
- Returns:
string
- Attachment.runtimeId()¶
Return the uuid identifying this attachment.
It is computed from what the attachment is, so the same declaration yields the same id in any Definitions. Definitions says what each kind is computed from.
- Returns:
ValueUUId
- Attachment.typeKey()¶
Return the type key<elementType>.
- Returns:
TypeKey
- Attachment.typeName()¶
Return the TypeName.
- Returns:
TypeName
- class AttachmentGetting()¶
Read access to the documents attached to a set of keys.
keys, has, get, enumerate, and diffKeys against another state.
Note: Not directly instantiable.
exported from
index.d- AttachmentGetting.attachment(attachmentRuntimeId)¶
- Return the attachment attachmentRuntimeId names, or throw if the definitions hold
none.
- Arguments:
attachmentRuntimeId (ValueUUId)
- Returns:
Attachment
- AttachmentGetting.definitions()¶
Return the Definitions every value reachable here is typed by.
- Returns:
DefinitionsConst
- AttachmentGetting.enumerate(attachment, encoded)¶
Return every (key, document) pair attachment holds.
Passing encoded false returns each document as a Value rather than a native object.
- Arguments:
attachment (Attachment)
encoded (boolean | null)
- Returns:
[ValueKey, Value | OutputValue][]
- AttachmentGetting.get(attachment, key)¶
Return a ValueOptional over the document attachment holds at key.
Always a ValueOptional, never undefined: ask isNil() whether it holds anything, and unwrap() for the document itself.
An absent document answers a nil ValueOptional; a key of another concept than the one attachment files throws, so isNil() reports absence and never a mismatched key.
The document comes back as a copy; mutating it does not reach what is stored.
- Arguments:
attachment (Attachment)
key (ValueKey)
- Returns:
ValueOptional
- AttachmentGetting.has(attachment, key)¶
Return true if attachment holds a document at key.
- Arguments:
attachment (Attachment)
key (ValueKey)
- Returns:
boolean
- AttachmentGetting.keys(attachment)¶
Return every key attachment holds a document for.
The set is taken now: a later write does not reach it.
- Arguments:
attachment (Attachment)
- Returns:
ValueSet<ValueKey>
- static AttachmentGetting.diffKeys(currentAttachmentGetting, otherAttachmentGetting, attachment)¶
Return the tuple (addedKeys, removedKeys, differentKeys, sameKeys).
Computed for attachment, between currentAttachmentGetting and otherAttachmentGetting.
addedKeys: keys present in ‘other’ and not in ‘current’.
removedKeys: keys present in ‘current’ and not in ‘other’.
differentKeys: documents present in both but not equal.
sameKeys: documents present in both and equal.
- Arguments:
currentAttachmentGetting (AttachmentGetting)
otherAttachmentGetting (AttachmentGetting)
attachment (Attachment)
- Returns:
[ValueSet<OutputValue>, ValueSet<OutputValue>, ValueSet<OutputValue>, ValueSet<OutputValue>]
- class AttachmentMutating()¶
Expresses fine-grained mutations of the documents attached to keys.
No key can be removed once written. To make one hold nothing, declare the attachment over an optional document type and set it to nil: the key remains, holding nothing. A Database, which keeps only the current state, has delete instead.
What a key holds can be replaced whole with set, or rewritten inside the document with update, the subtract* methods and removeInXarray - but the key itself stays.
Every write is checked against the model before it is recorded: the document against the attachment’s type, the key against the concept the attachment files, the path against the shape of the document, and the value against what that path holds. Any of them throws, and nothing is written. A key that does not exist yet is created rather than refused.
Note: Not directly instantiable.
exported from
index.d- Extends:
AttachmentGetting
- AttachmentMutating.attachment(attachmentRuntimeId)¶
- Return the attachment attachmentRuntimeId names, or throw if the definitions hold
none.
- Arguments:
attachmentRuntimeId (ValueUUId)
- Returns:
Attachment
- AttachmentMutating.attachmentGetting()¶
Return this object seen through the AttachmentGetting interface.
The two are views of one object: what comes back reads the same documents, not a copy, so a later write through this one is visible there. AttachmentMutating does derive from AttachmentGetting - in C++ and in both bindings - so passing it where a reader is expected already works; this exists to say which view you mean.
- Returns:
AttachmentGetting
- AttachmentMutating.definitions()¶
Return the Definitions every value reachable here is typed by.
- Returns:
DefinitionsConst
- AttachmentMutating.diff(attachment, key, value, recursive)¶
Write only what differs between value and what attachment holds at key.
recursive computes the difference field by field inside a structure, instead of replacing it whole.
This writes; AttachmentGetting.diffKeys only reports.
- Arguments:
attachment (Attachment)
key (ValueKey)
value (InputValue)
recursive (boolean | null)
- AttachmentMutating.enumerate(attachment, encoded)¶
Return every (key, document) pair attachment holds.
Passing encoded false returns each document as a Value rather than a native object.
- Arguments:
attachment (Attachment)
encoded (boolean | null)
- Returns:
[ValueKey, Value | OutputValue][]
- AttachmentMutating.get(attachment, key)¶
Return a ValueOptional over the document attachment holds at key.
Always a ValueOptional, never undefined: ask isNil() whether it holds anything, and unwrap() for the document itself.
An absent document answers a nil ValueOptional; a key of another concept than the one attachment files throws, so isNil() reports absence and never a mismatched key.
The document comes back as a copy; mutating it does not reach what is stored.
- Arguments:
attachment (Attachment)
key (ValueKey)
- Returns:
ValueOptional
- AttachmentMutating.has(attachment, key)¶
Return true if attachment holds a document at key.
- Arguments:
attachment (Attachment)
key (ValueKey)
- Returns:
boolean
- AttachmentMutating.insertInXarray(attachment, key, path, beforePosition, newPosition, value)¶
- Insert value at newPosition, before beforePosition, in the xarray at path inside the
document attachment holds at key.
- Arguments:
attachment (Attachment)
key (ValueKey)
path (PathConst)
beforePosition (ValueUUId)
newPosition (ValueUUId)
value (InputValue)
- AttachmentMutating.keys(attachment)¶
Return every key attachment holds a document for.
The set is taken now: a later write does not reach it.
- Arguments:
attachment (Attachment)
- Returns:
ValueSet<ValueKey>
- AttachmentMutating.removeInXarray(attachment, key, path, position)¶
Remove position from the xarray at path, in the document attachment holds at key.
- Arguments:
attachment (Attachment)
key (ValueKey)
path (PathConst)
position (ValueUUId)
- AttachmentMutating.set(attachment, key, value)¶
Write value into attachment at key, replacing what was there.
The value is copied in: mutating it afterwards does not reach what was written, and writing the same object under two keys stores two independent documents.
- Arguments:
attachment (Attachment)
key (ValueKey)
value (InputValue)
- AttachmentMutating.subtractInMap(attachment, key, path, value)¶
- Remove from the map at path, in the document attachment holds at key, the entries
whose map key is in value.
- Arguments:
attachment (Attachment)
key (ValueKey)
path (PathConst)
value (InputValue)
- AttachmentMutating.subtractInSet(attachment, key, path, value)¶
- Remove the elements of value from the set at path, in the document attachment holds
at key.
- Arguments:
attachment (Attachment)
key (ValueKey)
path (PathConst)
value (InputValue)
- AttachmentMutating.unionInMap(attachment, key, path, value)¶
- Add the entries of value to the map at path, in the document attachment holds at
key, replacing the map keys already there.
- Arguments:
attachment (Attachment)
key (ValueKey)
path (PathConst)
value (InputValue)
- AttachmentMutating.unionInSet(attachment, key, path, value)¶
- Add the elements of value to the set at path, in the document attachment holds at
key.
- Arguments:
attachment (Attachment)
key (ValueKey)
path (PathConst)
value (InputValue)
- AttachmentMutating.update(attachment, key, path, value)¶
Write value at path, inside the document attachment holds at key.
- Arguments:
attachment (Attachment)
key (ValueKey)
path (PathConst)
value (InputValue)
- AttachmentMutating.updateInMap(attachment, key, path, value)¶
Update the entries of the map at path from those of value.
The map sits in the document attachment holds at key.
Only map keys already there are written; a map key that only value carries is ignored - unionInMap inserts it instead.
- Arguments:
attachment (Attachment)
key (ValueKey)
path (PathConst)
value (InputValue)
- AttachmentMutating.updateInXarray(attachment, key, path, position, value)¶
- Write value at position, in the xarray at path inside the document attachment holds
at key.
- Arguments:
attachment (Attachment)
key (ValueKey)
path (PathConst)
position (ValueUUId)
value (InputValue)