Record handles (ref)

One rule makes the whole surface guessable:

> bs.records is a collection. bs.records.ref(42) is a record handle. > A record's relation is again a collection.

What ref is

ref(id) returns a lightweight handle to one record. It is lazy — it makes no API call until you ask for something. You can also pass a model you already have, which seeds the handle's cache.

c = bs.records.ref(42)      # 0 API calls — just a reference
c = bs.records(42)          # Python sugar for .ref(42)
rec = c.get()               # 1 call — fetch + cache
c.field_values()            # 0 calls if cached, else 1
const c = bs.records.ref(42);      // .ref() everywhere (PHP/TS/Go); Python also bs.records(42)
$c = $bs->records->ref(42);
c := bs.Records.Ref(42)            // or Ref(existingModel)

What a handle can do

Method Cost Notes
get() 1 fetch and cache the record
update(data) 1 update and re-cache
delete() 1 delete by id
field_values() 0 cached / 1 field values keyed by field name
expand([...]) 1 per relation eager-load related records (phase 3)
<belongsTo>() e.g. c.space() 1 (0 if cached) follow a foreign key to the related record
<hasMany>() e.g. c.labels() a relation-collection (see relations-expand.md)

Why a handle and not of()

The earlier of(entity) navigator required you to fetch the model first and read backwards. ref reads forward ("record 42 → its labels"), works from a bare id without a fetch, and groups everything about one record under one autocomplete. of() remains as a @deprecated alias during the transition.

Models stay pure data — no hidden I/O on a model object. The handle holds the cache and every method documents its API-call cost.