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

Attachment

The declaration binding a concept to a value type

Attachment Interfaces

Class

Description

AttachmentGetting

Read access to the documents attached to a set of keys

AttachmentMutating

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)