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: stringDescription: Model type name (e.g., ‘task’, ‘user’, ‘post’)
Example: 'task', 'user'
id
id: stringDescription: Unique model ID (usually UUID)
Example: 'abc-123-def-456'
v
v?: numberDescription: 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 // falseFlow:
- WireRow stored in ObjectPool
- IdentityMap creates/caches model instance
- Model properties read from
row.p - Model mutations update
row.poptimistically
See Also
- SyncFrame - Protocol format for sync operations
- ObjectPool Concept - How WireRow is stored
- IdentityMap - Converts WireRow to Model
- StorageAdapter - Storage interface using WireRow