Skip to Content
ReferenceClient APIStorageAdapter

StorageAdapter

Interface for local storage adapters. Manages client-side data persistence.

Import

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

Interface Definition

Complete interface from implementation:

export interface StorageAdapter { // Required: Row operations getRow(t: string, id: string): Promise<WireRow | null> putRow(row: WireRow): Promise<void> deleteRow(t: string, id: string): Promise<void> // Optional: Bulk operations getRows?(t: string, ids: string[]): Promise<WireRow[]> putRows?(rows: WireRow[]): Promise<void> deleteRows?(items: Array<{ t: string, id: string }>): Promise<void> withTransaction?<T>(fn: () => Promise<T>): Promise<T> // Optional: Fast hydration listByType?(t: string): Promise<WireRow[]> listByIndex?(t: string, indexKey: string, indexVal: string): Promise<WireRow[]> // Required: Sync state getLastSyncId(): Promise<number> setLastSyncId(n: number): Promise<void> // Optional: Clear all clearAll?(): Promise<void> // Required: Transaction queue enqueueTx(op: { id: string, t: string, mid: string, patch: any, prev: any, op?: 'i' | 'u' | 'd' }): Promise<void> dequeueTx(id: string): Promise<void> listTx(): Promise<Array<{ id: string, t: string, mid: string, patch: any, prev: any, op?: 'i' | 'u' | 'd' }>> }

Total: 15 methods (8 required, 7 optional)


Required Methods

getRow()

getRow(t: string, id: string): Promise<WireRow | null>

Get a single row by type and ID.

Parameters:

ParameterTypeDescription
tstringModel type name
idstringModel ID

Returns: Promise<WireRow | null> - Row data or null if not found

Example:

const row = await storage.getRow('task', 'abc-123') if (row) { console.log(row.p.title) }

putRow()

putRow(row: WireRow): Promise<void>

Store a single row.

Parameters:

ParameterTypeDescription
rowWireRowComplete row data

Example:

await storage.putRow({ t: 'task', id: 'abc-123', v: 1, p: { title: 'My Task', done: false } })

deleteRow()

deleteRow(t: string, id: string): Promise<void>

Delete a single row.

Parameters:

ParameterTypeDescription
tstringModel type name
idstringModel ID

Example:

await storage.deleteRow('task', 'abc-123')

getLastSyncId()

getLastSyncId(): Promise<number>

Get the last processed sync ID.

Returns: Promise<number> - Last sync ID (0 if never synced)

Example:

const lastSyncId = await storage.getLastSyncId() console.log(`Last synced at: ${lastSyncId}`)

setLastSyncId()

setLastSyncId(n: number): Promise<void>

Store the last processed sync ID.

Parameters:

ParameterTypeDescription
nnumberSync ID to store

Example:

await storage.setLastSyncId(42)

enqueueTx()

enqueueTx(op: { id: string t: string mid: string patch: any prev: any op?: 'i' | 'u' | 'd' }): Promise<void>

Add a transaction to the pending queue.

Parameters:

FieldTypeDescription
idstringTransaction ID (client-generated)
tstringModel type
midstringModel ID
patchanyData to apply
prevanyPrevious data (for rollback)
op'i' | 'u' | 'd'Operation: insert, update, delete

Example:

await storage.enqueueTx({ id: 'tx-123', t: 'task', mid: 'abc-123', patch: { title: 'Updated' }, prev: { title: 'Original' }, op: 'u' })

dequeueTx()

dequeueTx(id: string): Promise<void>

Remove a transaction from the queue (after server confirms).

Parameters:

ParameterTypeDescription
idstringTransaction ID

Example:

await storage.dequeueTx('tx-123')

listTx()

listTx(): Promise<Array<{ id: string t: string mid: string patch: any prev: any op?: 'i' | 'u' | 'd' }>>

List all pending transactions.

Returns: Promise<Transaction[]> - Array of pending transactions

Example:

const pending = await storage.listTx() console.log(`${pending.length} transactions pending`)

Optional Bulk Operations

getRows()

getRows?(t: string, ids: string[]): Promise<WireRow[]>

Get multiple rows at once (performance optimization).

Parameters:

ParameterTypeDescription
tstringModel type name
idsstring[]Array of model IDs

Returns: Promise<WireRow[]> - Array of rows (missing IDs omitted)

Performance: More efficient than calling getRow() multiple times.

Example:

const rows = await storage.getRows('task', ['id-1', 'id-2', 'id-3'])

putRows()

putRows?(rows: WireRow[]): Promise<void>

Store multiple rows at once (performance optimization).

Parameters:

ParameterTypeDescription
rowsWireRow[]Array of rows

Performance: More efficient than calling putRow() multiple times.

Example:

await storage.putRows([ { t: 'task', id: '1', p: { title: 'A' } }, { t: 'task', id: '2', p: { title: 'B' } } ])

deleteRows()

deleteRows?(items: Array<{ t: string, id: string }>): Promise<void>

Delete multiple rows at once (performance optimization).

Parameters:

ParameterTypeDescription
itemsArray<{ t, id }>Array of type/ID pairs

Example:

await storage.deleteRows([ { t: 'task', id: '1' }, { t: 'task', id: '2' } ])

withTransaction()

withTransaction?<T>(fn: () => Promise<T>): Promise<T>

Execute function within a database transaction.

Parameters:

ParameterTypeDescription
fn() => Promise<T>Function to execute

Returns: Promise<T> - Result from function

Behavior: Ensures atomicity (all or nothing).

Example:

await storage.withTransaction(async () => { await storage.putRow(row1) await storage.putRow(row2) // Both succeed or both fail })

Optional Hydration Methods

listByType()

listByType?(t: string): Promise<WireRow[]>

List all rows of a specific type.

Parameters:

ParameterTypeDescription
tstringModel type name

Returns: Promise<WireRow[]> - All rows of type

Performance: Enables fast type hydration.

Example:

const allTasks = await storage.listByType('task')

listByIndex()

listByIndex?( t: string, indexKey: string, indexVal: string ): Promise<WireRow[]>

List rows by indexed field (for relationships).

Parameters:

ParameterTypeDescription
tstringModel type name
indexKeystringIndex field name (e.g., ‘authorId’)
indexValstringIndex value

Returns: Promise<WireRow[]> - Matching rows

Performance: Enables fast collection hydration.

Example:

// Get all tasks by author const tasks = await storage.listByIndex('task', 'authorId', 'user-123')

clearAll()

clearAll?(): Promise<void>

Delete all stored data (for logout/reset).

Example:

// Clear on logout await storage.clearAll()

Implementation Example

See DrizzleAdapter for a complete implementation.

Basic Implementation Structure

import type { StorageAdapter, WireRow } from '@gluonic/client' export class MyAdapter implements StorageAdapter { // Required async getRow(t: string, id: string): Promise<WireRow | null> { // Implementation } async putRow(row: WireRow): Promise<void> { // Implementation } async deleteRow(t: string, id: string): Promise<void> { // Implementation } async getLastSyncId(): Promise<number> { // Implementation } async setLastSyncId(n: number): Promise<void> { // Implementation } async enqueueTx(op: any): Promise<void> { // Implementation } async dequeueTx(id: string): Promise<void> { // Implementation } async listTx(): Promise<any[]> { // Implementation } // Optional (recommended) async listByType(t: string): Promise<WireRow[]> { // Fast type hydration } async listByIndex(t: string, key: string, val: string): Promise<WireRow[]> { // Fast collection loading } }

Internal Tables

Storage adapters typically create these internal tables:

sync_tx_queue

Stores pending transactions:

  • id (string) - Transaction ID
  • t (string) - Model type
  • mid (string) - Model ID
  • patch (JSON) - Data to apply
  • prev (JSON) - Previous data
  • op (string) - Operation (‘i’, ‘u’, ‘d’)

sync_meta

Stores sync metadata:

  • key (string) - ‘lastSyncId’
  • value (number) - Last sync ID

These tables are managed by the storage adapter. Gluonic creates them automatically via the adapter.


See Also

Last updated on