Data model
Tuples
The smallest unit of data in XDB: an immutable path, attribute, and typed value.
A tuple is an attribute value at a record path: xdb://ns/schema/id#attr = value. It is the smallest unit of record data in XDB. A record groups tuples that share a path.
Structure
A tuple contains:
| Component | Type | Description |
|---|---|---|
| Path | *URI | The record URI (NS + Schema + ID) |
| Attr | string | The attribute name. Dots separate nested names |
| Value | *Value | The typed value |
┌────────────────────────────────────────────────┐│ Tuple │├──────────┬──────────┬──────────────────────────┤│ Path │ Attr │ Value ││ (URI) │ (string) │ (typed: str, int, ...) │└──────────┴──────────┴──────────────────────────┘A tuple is immutable after creation. Its path, attribute, and value cannot change.
Creating Tuples
tuple := core.NewTuple("com.example/posts/post-123", "title", "Hello World")NewTuple panics on invalid input. The path argument is a URI path without
the xdb:// scheme. XDB infers the value type from the Go type. See
Types for the supported types.
Usually you create tuples through a Record. The record owns the shared path:
record := core.NewRecord("com.example", "posts", "post-123"). Set("title", "Hello World")
tuple := record.Get("title")Accessing Data
Path Components
tuple.Path() // *URI — record URI (without the attribute)tuple.Attr() // string — attribute nametuple.URI() // *URI — full URI, including the attribute fragmenttuple.Value() // *Value — typed value
tuple.Path().NS() // string — namespacetuple.Path().Schema() // string — schema nametuple.Path().ID() // string — record identifierTyped Value Accessors
A tuple has As* methods (AsStr(), AsInt(), AsBool(), and more) that
return the value with its type. Each method returns (T, error). If the
attribute is missing, the tuple is nil, for example record.Get("tpyo"). The
As* methods on a nil tuple return the zero value and
ErrAttrNotFound. This makes a typo different from an
empty value. See Types for the full list of accessors.
title, err := record.Get("title").AsStr()Dot-Separated Attributes
An attribute name can contain dots to represent nested data, for example author.name or profile.address.city. The JSON encoder unfolds these attributes into nested objects. See Encoding for details.
Tuples in Stores
A store can read or write an individual attribute through its #attr URI:
st := store.New(xdbmemory.NewDriver())
// Patch tuples into records. The store creates the record if it is// absent and leaves other attributes unchanged. Tuples can span records.err := st.PutTuples(ctx, core.NewTuple("com.example/posts/post-123", "title", "Hello"), core.NewTuple("com.example/posts/post-123", "rating", 4.5),)
// Point-read one tuple. If the record or the attribute is absent, the// error is core.ErrNotFound.tuple, err := st.GetTuple(ctx, core.MustParseURI("xdb://com.example/posts/post-123#title"))
// Batch point reads omit absent attributes and return no error for them.tuples, err := st.GetTuples(ctx, uris...)
// Delete single tuples. This is idempotent. When the last tuple of a// record is deleted, the record is deleted.err = st.DeleteTuples(ctx, core.MustParseURI("xdb://com.example/posts/post-123#rating"))A record starts to exist when its first tuples are written. It stops existing
when its last tuple is deleted. Schema policy applies to tuple writes in
the same way as to other writes. Types are checked, strict mode rejects
undeclared attributes, and a required attribute cannot be deleted from a
record.
The API and the CLI accept attribute-level URIs in the same way.
xdb records get xdb://com.example/posts/post-123#title returns only that
attribute. xdb records delete xdb://com.example/posts/post-123#title --force
deletes only that tuple.