Query interface
To connect to different backends, Forest Admin abstracts away their differences.
Each one of the available data sources "speaks" the language of the API it is targeting from one side and exposes the Forest Admin Query Interface on the other one.
This API is by far not a full-featured ORM: its objective is to be "just enough" to fuel Forest Admin.
Writing an abstraction layer is full of compromises: small enough so that it can be written on top of APIs which may not be very capable but large enough so that all Forest Admin features can be implemented on top of them.
When customizing your Forest Admin with custom code (creating new actions, fields, ...), you can either access your data using the Forest Admin Query Interface or using the native driver. It makes no difference for the admin panel.
- | Forest Admin Query Interface | Native Driver |
---|---|---|
Learning curve | Use the same query interface for any SaaS | Different API for each database / SaaS |
Differentiating features | Can make cross data-source requests | Use all features of the underlying API |
This example shows the same segment implemented using both methods.
Using the forest admin query interface:
collection.addSegment('mySegment', async context => {
const rows = await context.dataSource
.getCollection('orders')
.aggregate({}, { operation: 'Count', groups: [{ field: 'product_id' }] }, 10);
return { field: 'id', operator: 'In', value: rows.map(r => r['product_id']) };
});
Using a native driver:
const client = new Client({ host: 'localhost', database: 'myDb', port: 5432 });
client.connect();
collection.addSegment('mySegment', async context => {
const { rows } = await client.query(`
SELECT product_id, COUNT(*)
FROM orders
GROUP BY product_id
ORDER BY count DESC
LIMIT 10;
`);
return { field: 'id', operator: 'In', value: rows.map(r => r['product_id']) };
});
All parameters are explained in depth on the following pages:
interface DataSource {
/** Retrieve list of all collection within the data source */
get collections(): Collection[];
/** Get collection by name */
getCollection(name: string): Collection;
}
interface Collection {
/** The schema contains the structure and capabilities of the collection */
get schema(): CollectionSchema;
/** Create new records */
create(data: RecordData[]): Promise<RecordData[]>;
/** List records matching filter */
list(filter: PaginatedFilter, projection: Projection): Promise<RecordData[]>;
/** Update records matching filter */
update(filter: Filter, patch: RecordData): Promise<void>;
/** Delete records matching filter */
delete(filter: Filter): Promise<void>;
/** Compute aggregated version of records matching filter */
aggregate(filter: Filter, aggregation: Aggregation, limit?: number): Promise<AggregateResult[]>;
}
Last modified 1mo ago