API Reference
interfaces
Relationoptions

@coasys/ad4m / Exports / RelationOptions

Interface: RelationOptions

Options for relation decorators (@HasMany, @HasOne, @BelongsToOne, @BelongsToMany).

Table of contents

Properties

Properties

datatype

• Optional datatype: string

SHACL sh:datatype for the relation's target values. Set when the relation holds encoded literal values (e.g. "xsd:string" for a HasMany<string> that stores plain strings). The executor uses this to decode literal:<type>:<value> wire form on hydration. Omit for URI relations that point at other model instances.

Mutually exclusive with target: a relation holds either literals or model instances. Combines with through or getter.

Example

@HasMany({ through: "run://source", datatype: "xsd:string" })
sources: string[] = [];

Defined in

core/src/model/decorators.ts:916 (opens in a new tab)


filter

• Optional filter: boolean

Whether to auto-generate a DB-level conformance filter when target is set. Defaults to true when target is present — the query will only return linked nodes whose shape matches the target model (required properties, flags, etc.). Set to false to opt out of filtering while keeping hydration capability.

Defined in

core/src/model/decorators.ts:877 (opens in a new tab)


getter

• Optional getter: string

Custom getter to resolve the relation values. Use this for custom graph traversals. The expression can reference 'Base' which will be replaced with the instance's base expression. Example: "SELECT ?target WHERE { ?target flux://has_reply . }"

Mutually exclusive with through — a getter replaces link-based resolution, so there is no predicate to add to or remove from. When getter is provided the relation is read-only (no adder/remover actions are generated). The exception is readOnly: true, where through names the predicate the getter reads and becomes the shape's path.

Combines with target, which names the class the traversal's values hydrate into — without it include has no shape to resolve and the relation can only return bare URIs. Also combines with where, applied as a post-getter filter against the target class.

Example

Traversing a reified edge — a connection stored as a record rather than a predicate, so no through can express it:

@HasMany({
  getter: `SELECT ?target WHERE {
    ?citation <paper://cites_from> <Base> .
    ?citation <paper://cites_to> ?target .
  }`,
  target: () => Paper,
})
cited: Paper[] = [];

Defined in

core/src/model/decorators.ts:860 (opens in a new tab)


instantiateAs

• Optional instantiateAs: () => Ad4mModelLike[]

Type declaration

▸ (): Ad4mModelLike[]

The model classes a polymorphic result may be constructed as.

Classification happens in the executor, structurally — there is no rdf:type triple to read, so a target's class is derived from the flags and required properties it carries. What cannot cross the wire is the TypeScript constructor, so this names the classes this side can build. @Model already records each class's name on the class itself, so the name → class mapping is derived from the list rather than restated alongside it.

This is advisory, not a constraint. It never narrows what the query returns and never excludes a target: a class missing from the list arrives as plain JSON carrying its class name, so partial knowledge degrades instead of failing. Declaring what this call site can construct is a different statement from declaring what the relation may contain — a heterogeneous relation is open by definition, and a list that silently dropped unrecognised members would defeat the point of reading it polymorphically at all. Constraining a read to particular classes belongs in the query, not here.

A thunk rather than an array, for the same reason target is one: it is evaluated at query time, so a class defined later in a circular import graph still resolves.

Returns

Ad4mModelLike[]

Defined in

core/src/model/decorators.ts:970 (opens in a new tab)


interpretationHint

• Optional interpretationHint: string

Natural-language hint describing what this relation MEANS semantically — the sentence-level rationale for when to use it, not just its structural shape. Emitted as an ad4m://interpretation_hint link on the SHACL property node; read back by the Rust harness (ClassProposeShape. relations[N].hint) and rendered into the _propose_link_child tool's predicate field description so the LLM knows which relation applies to which situation instead of guessing from the predicate name alone.

Example

@HasMany(() => Belief, {
  through: "ns://basedOn",
  interpretationHint: "The prior beliefs this intention derives from.",
})
basedOn: Belief[] = [];

Defined in

core/src/model/decorators.ts:1020 (opens in a new tab)


local

• Optional local: boolean

Whether the link is stored locally (not shared on the network)

Defined in

core/src/model/decorators.ts:870 (opens in a new tab)


ordering

• Optional ordering: Object

Give this collection a user-controlled order that survives concurrent edits.

A @HasMany is a set of links, and hydration sorts them by link timestamp. That is right for an append-only collection — a transcript, a message thread — where timestamp order is the order. It cannot express a sequence somebody chose: a kanban column, a playlist, the blocks of a post.

Declaration only, for now. Setting this emits ad4m://ordering on the property shape, where the executor reads it back — but no read or write path acts on it yet, so a relation declaring it still hydrates by link timestamp exactly as one that does not. Wiring save and hydration to the declaration is the next change; nothing about how you write the relation will change when it lands — assign the array in the order you want and save.

Ordering is declared in the type system, rather than passed per query, so that every writer gets it once it is wired: the ORM, MCP agents, raw WS-RPC callers, another app sharing the neighbourhood. Implemented client-side it would order only what this client wrote.

Example

@HasMany(() => Task, {
  through: "kanban://has_task",
  ordering: { strategy: "linkedList" },
})
tasks: Task[] = [];

Type declaration

NameType
strategy"linkedList"

Defined in

core/src/model/decorators.ts:1001 (opens in a new tab)


polymorphic

• Optional polymorphic: boolean

Hydrate each target as the class it actually is, rather than as the class this relation declares.

A heterogeneous relation has no single right target. Declaring the base class loses every subclass property — the executor hydrates against the shape it is given, so an ImagePost read as a Post arrives with its own fields simply absent, not merely mislabelled. Declaring nothing leaves include with no shape to resolve at all.

With this set, the targets are classified, grouped by concrete class, and hydrated against their own shapes — one query per distinct class present, not per instance.

Pair with instantiateAs so the results become instances of the right model class rather than plain objects.

Example

@HasMany({
  through: "we://children",
  polymorphic: true,
  instantiateAs: () => [TextBlock, ImageBlock],
})
children: Post[] = [];

Defined in

core/src/model/decorators.ts:944 (opens in a new tab)


readOnly

• Optional readOnly: boolean

A relation read through through that this model must not write: no add*/remove*/set* methods and no adder or remover actions. Pair it with getter when the stored links need filtering on the way out (only those signed by their target, say) but the predicate should still be the shape's path, so a subscription re-runs when one lands.

Defined in

core/src/model/decorators.ts:868 (opens in a new tab)


target

• Optional target: () => Ad4mModelLike

Type declaration

▸ (): Ad4mModelLike

The target model class (use a thunk to avoid circular-dependency issues). Optional for untyped string relations. Combines with getter, where it names the class the traversal's values hydrate into.

Returns

Ad4mModelLike

Defined in

core/src/model/decorators.ts:830 (opens in a new tab)


through

• Optional through: string

The predicate URI used to link the two models. Defaults to 'ad4m://has_child' when omitted. Cannot be combined with getter, except on a readOnly relation.

Defined in

core/src/model/decorators.ts:827 (opens in a new tab)


where

• Optional where: Where

Filter constraints on the linked target nodes, using the same query DSL as Model.query().where(...). Property names reference the target model's properties (resolved via target metadata).

When target is set and where is omitted, conformance conditions are auto-derived from the target shape (flags + required properties). Providing where overrides this auto-derivation.

Mutually exclusive with filter: false. Combines with getter, where it is applied as a post-getter filter against the target class.

Example

@HasMany(() => Message, {
  through: "flux://entry_type",
  where: { status: "active", priority: { gte: 3 } }
})
activeMessages: Message[] = []

Defined in

core/src/model/decorators.ts:899 (opens in a new tab)