Custom adapters
Create a custom adapter when an application has a specialized source that does not fit the built-in memory adapter or Pro SQLite, JSON, and REST adapters.
The simplest approach is to extend FdcDataAdapter and implement the operations your source supports.
class CustomerServiceAdapter extends FdcDataAdapter {
CustomerServiceAdapter(this.service)
: super(
readOnly: true,
capabilities: const FdcDataAdapterCapabilities(
filtering: true,
sorting: true,
paging: true,
totalCount: true,
search: true,
),
);
final CustomerService service;
@override
Future<FdcDataLoadResult> load(FdcDataLoadRequest request) async {
final result = await service.loadCustomers(request);
return FdcDataLoadResult(
rows: result.rows,
totalCount: result.totalCount,
);
}
}
Declare capabilities accurately
FdcDataAdapterCapabilities is part of the adapter contract. The dataset validates requested operations before calling the adapter.
Do not advertise an operation and silently ignore it. For example, an adapter that reports paging support must honor page request values and return rows for that requested slice.
Writable adapters
A writable adapter sets readOnly: false and implements applyUpdates().
The method receives an FdcChangeSet containing pending dataset changes and returns FdcDataApplyResult. Backend-confirmed values can be returned to synchronize generated keys or normalized fields back into the dataset.
Storage-specific validation can be added through validateStorageValue(). Backend exceptions can be translated into structured row-level errors through mapApplyException().
Aggregates
When an adapter advertises aggregate support, override aggregate() and calculate values over the complete effective query result. Aggregate requests contain filters and search state but no page limit.
Synchronous local adapters
Local adapters that can load immediately may also implement IFdcSynchronousDataAdapter. This is intended for genuinely synchronous sources; async-only adapters should use the normal asynchronous load() contract.