Skip to Content
ReferenceClient APIBatchLoaderAdapter

BatchLoaderAdapter

Interface for batch loading collections from server. Enables performance optimization by coalescing multiple collection requests.

Import

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

Interface Definition

Exact definition from implementation:

export type BatchLoaderAdapter = { fetchCollection: ( t: string, indexKey: string, indexVal: string ) => Promise<WireRow[]> fetchCollections?: ( keys: Array<{ t: string, indexKey: string, indexVal: string }> ) => Promise<Record<string, WireRow[]>> fetchByIds?: ( t: string, ids: string[] ) => Promise<WireRow[]> }

Total: 3 methods (1 required, 2 optional). Optional methods enable batch coalescing for better performance.


Methods

fetchCollection()

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

Fetch a collection by indexed field (e.g., all tasks for a team).

Parameters:

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

Returns: Promise<WireRow[]> - Array of matching rows

Example:

// Fetch all tasks for team 'team-123' const tasks = await batchLoader.fetchCollection( 'task', 'teamId', 'team-123' )

Server Request:

GET /sync/v1/batch?t=task&indexKey=teamId&indexVal=team-123

fetchCollections() (Optional)

fetchCollections?( keys: Array<{ t: string, indexKey: string, indexVal: string }> ): Promise<Record<string, WireRow[]>>

Fetch multiple collections in a single request (performance optimization).

Parameters:

ParameterTypeDescription
keysArray<{ t, indexKey, indexVal }>Array of collection queries

Returns: Promise<Record<string, WireRow[]>> - Map of query keys to rows

Example:

const results = await batchLoader.fetchCollections([ { t: 'task', indexKey: 'teamId', indexVal: 'team-1' }, { t: 'task', indexKey: 'teamId', indexVal: 'team-2' }, { t: 'issue', indexKey: 'projectId', indexVal: 'proj-1' } ]) // Results keyed by query results['task:teamId:team-1'] // Task[] for team-1 results['task:teamId:team-2'] // Task[] for team-2 results['issue:projectId:proj-1'] // Issue[] for proj-1

Performance: Reduces 3 requests to 1.

fetchByIds() (Optional)

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

Fetch specific models by IDs in a single request.

Parameters:

ParameterTypeDescription
tstringModel type name
idsstring[]Array of model IDs

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

Example:

const tasks = await batchLoader.fetchByIds( 'task', ['id-1', 'id-2', 'id-3'] )

Performance: More efficient than fetching IDs individually.


Default Implementation

Default HTTP-based batch loader:

const defaultBatchLoader: BatchLoaderAdapter = { async fetchCollection(t, indexKey, indexVal) { const params = new URLSearchParams({ t, indexKey, indexVal }) const response = await fetch(`/sync/v1/batch?${params}`) if (!response.ok) { throw new Error(`Batch load failed: ${response.statusText}`) } const data = await response.json() return data.rows || [] }, async fetchByIds(t, ids) { const response = await fetch('/sync/v1/batch', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ t, ids }) }) const data = await response.json() return data.rows || [] } }

Batching & Coalescing

When fetchCollections is implemented, Gluonic automatically coalesces requests:

// Component renders 50 teams teams.forEach(team => { console.log(team.tasks.length) // Triggers lazy load }) // Without fetchCollections: 50 individual requests // fetchCollection('task', 'teamId', 'team-1') // fetchCollection('task', 'teamId', 'team-2') // ... 48 more // With fetchCollections: 1 batched request after ~50ms // fetchCollections([ // { t: 'task', indexKey: 'teamId', indexVal: 'team-1' }, // { t: 'task', indexKey: 'teamId', indexVal: 'team-2' }, // ... all 50 // ])

Performance: Reduces 50 requests to 1, saves ~5 seconds.


Custom Implementation

GraphQL Example

import type { BatchLoaderAdapter } from '@gluonic/client' class GraphQLBatchLoader implements BatchLoaderAdapter { async fetchCollection(t, indexKey, indexVal) { const query = ` query FetchCollection($type: String!, $key: String!, $val: String!) { collection(type: $type, indexKey: $key, indexVal: $val) { t id v p } } ` const response = await fetch('/graphql', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ query, variables: { type: t, key: indexKey, val: indexVal } }) }) const result = await response.json() return result.data.collection } async fetchCollections(keys) { // Batch query for all collections const queries = keys.map((key, i) => ` coll${i}: collection( type: "${key.t}", indexKey: "${key.indexKey}", indexVal: "${key.indexVal}" ) { t id v p } `).join('\n') const response = await fetch('/graphql', { method: 'POST', body: JSON.stringify({ query: `{ ${queries} }` }) }) const result = await response.json() // Convert to expected format const output: Record<string, WireRow[]> = {} keys.forEach((key, i) => { const queryKey = `${key.t}:${key.indexKey}:${key.indexVal}` output[queryKey] = result.data[`coll${i}`] }) return output } } // Use in SyncClient const client = SyncClient({ server: 'https://api.example.com', storage, models, batch: new GraphQLBatchLoader() })

Usage in Gluonic

BatchLoaderAdapter is used by:

  1. LazyCollection hydration - Load collection items
  2. ensureRowsByIds() - Load specific models
  3. Relationship navigation - Auto-load related data
// User accesses collection const tasks = team.tasks.elements // Internally triggers: // 1. Check storage first // 2. If not found, call batchLoader.fetchCollection('task', 'teamId', team.id) // 3. Cache result in storage // 4. Update pool

Performance Benefits

Without Batch Loader

// Each lazy collection triggers separate request team1.tasks.length // Request 1 team2.tasks.length // Request 2 team3.tasks.length // Request 3 // 50 teams = 50 requests 😔

With fetchCollections

// Coalesced into single batch team1.tasks.length team2.tasks.length team3.tasks.length // 50 teams = 1 request after 50ms ✓

Network Savings: 50x reduction in requests


Configuration

const client = SyncClient({ server: 'https://api.example.com/sync/v1', storage, models, batch: { fetchCollection: async (t, key, val) => { // Custom implementation }, fetchCollections: async (keys) => { // Optional: batch optimization }, fetchByIds: async (t, ids) => { // Optional: ID batch loading } } })

See Also

Last updated on