Skip to Content

WireRow

Flattened row data format used in ObjectPool and storage.

Import

import type { WireRow } from '@gluonic/client'

Type Definition

Exact definition from implementation:

export type WireRow = { t: string id: string v?: number p: Record<string, any> }

Fields

t

t: string

Description: Model type name (e.g., ‘task’, ‘user’, ‘post’)

Example: 'task', 'user'

id

id: string

Description: Unique model ID (usually UUID)

Example: 'abc-123-def-456'

v

v?: number

Description: Version number for optimistic concurrency control

Optional: May be omitted for models without versioning

Example: 1, 42

p

p: Record<string, any>

Description: Properties payload (all model fields)

Example: { title: 'My Task', done: false, createdAt: 1234567890 }


Complete Example

const wireRow: WireRow = { t: 'task', id: 'abc-123-def-456', v: 1, p: { title: 'Implement feature', done: false, assigneeId: 'user-789', createdAt: 1699564800000, updatedAt: 1699564800000 } }

Usage

ObjectPool

WireRow is the internal format stored in the ObjectPool:

// Get row from pool const row: WireRow | null = store.pool.get('task', taskId) if (row) { console.log(row.p.title) // Access properties } // Upsert row to pool store.pool.upsert({ t: 'task', id: 'abc-123', p: { title: 'New Task', done: false } })

StorageAdapter

Storage adapters work with WireRow format:

class MyStorageAdapter implements StorageAdapter { async getRow(t: string, id: string): Promise<WireRow | null> { // Return WireRow from database return { t, id, v: 1, p: { /* properties */ } } } async putRow(row: WireRow): Promise<void> { // Store WireRow in database await db.insert({ ...row }) } }

SyncFrame Transformation

Sync frames are converted to/from WireRow:

// SyncFrame (from server) const frame: SyncFrame = { sid: 42, t: 'task', id: 'abc-123', op: 'i', p: { title: 'New Task' } } // Converted to WireRow (for pool) const row: WireRow = { t: frame.t, id: frame.id, v: frame.v, p: frame.p }

Why WireRow?

The flattened WireRow format provides several benefits:

1. Uniform Storage

All models use the same format regardless of schema:

// Task { t: 'task', id: '1', p: { title: 'Task' } } // User { t: 'user', id: '2', p: { name: 'Alice' } } // Any model { t: string, id: string, p: Record<string, any> }

2. Simple Indexing

Easy to index by type or ID:

CREATE INDEX idx_type_id ON rows(t, id) CREATE INDEX idx_type ON rows(t)

3. Schema-less Storage

No need for separate tables per model:

// One table for all models await db.insert('rows', wireRow)

4. Model-Agnostic Pool

ObjectPool doesn’t need to know about model classes:

// Pool stores WireRows const pool = new Map<string, WireRow>() // IdentityMap creates model instances from WireRows const model = identityMap.getModel('task', 'abc-123')

Relationship to Models

Model instances are created from WireRows:

// WireRow in pool { t: 'task', id: 'abc-123', p: { title: 'My Task', done: false } } // Model instance from IdentityMap const task = useModel<Task>('task', 'abc-123') task.title // 'My Task' task.done // false

Flow:

  1. WireRow stored in ObjectPool
  2. IdentityMap creates/caches model instance
  3. Model properties read from row.p
  4. Model mutations update row.p optimistically

See Also

Last updated on