The adapter-commons package provides shared utilities, base classes, and types used by all Feathers database adapters. This is typically used when building custom database adapters.
Installation
npm install @feathersjs/adapter-commons
AdapterBase
Abstract base class that all database adapters extend from.
import { AdapterBase } from '@feathersjs/adapter-commons'
class MyAdapter<Result, Data, ServiceParams, PatchData> extends AdapterBase<
Result,
Data,
PatchData,
ServiceParams,
Options
> {
// Implement abstract methods
async _find(params) { /* ... */ }
async _get(id, params) { /* ... */ }
async _create(data, params) { /* ... */ }
async _update(id, data, params) { /* ... */ }
async _patch(id, data, params) { /* ... */ }
async _remove(id, params) { /* ... */ }
}
Constructor
options
AdapterServiceOptions
required
Base adapter optionsName of the id field property
Pagination configuration with default and max values
Allow multiple updates. true, false, or array of method names
Custom event names (deprecated, use service registration events option)
Custom query filters with converter functions
Additional query operators to allow
Properties
The name of the id property.
const idField = adapter.id // 'id' or '_id'
events
List of custom event names.
const events = adapter.events
options
The full adapter options object.
const options = adapter.options
Methods
getOptions
Get the merged options for a service call, combining base options with params.
const options = adapter.getOptions(params)
Merged options including params.adapter overrides
allowsMulti
Check if a method allows multiple updates.
const allowed = adapter.allowsMulti(method, params)
The method name (e.g., ‘create’, ‘patch’, ‘remove’)
Whether multiple updates are allowed for this method
sanitizeQuery
Convert and validate query parameters.
const query = await adapter.sanitizeQuery(params)
Service call parameters with query
Sanitized query with converted values
Abstract Methods
These methods must be implemented by the adapter:
abstract _find(params?: ServiceParams): Promise<Paginated<Result> | Result[]>
abstract _get(id: Id, params?: ServiceParams): Promise<Result>
abstract _create(data: Data | Data[], params?: ServiceParams): Promise<Result | Result[]>
abstract _update(id: Id, data: Data, params?: ServiceParams): Promise<Result>
abstract _patch(id: Id | null, data: PatchData, params?: ServiceParams): Promise<Result | Result[]>
abstract _remove(id: Id | null, params?: ServiceParams): Promise<Result | Result[]>
Query Filtering
filterQuery
Separate special query parameters from regular query.
import { filterQuery } from '@feathersjs/adapter-commons'
const { query, filters } = filterQuery(params.query, options)
The incoming query object
Custom filter definitions
result
{ query: Query, filters: object }
Separated query and filters objectQuery without special parameters
Object with $limit, $skip, $sort, $select, $or, $and
getLimit
Calculate the appropriate limit based on pagination settings.
import { getLimit } from '@feathersjs/adapter-commons'
const limit = getLimit(requestedLimit, paginate)
The requested limit value
The calculated limit (respecting max if set)
OPERATORS
Default query operators allowed by adapters.
import { OPERATORS } from '@feathersjs/adapter-commons'
console.log(OPERATORS)
// ['$in', '$nin', '$lt', '$lte', '$gt', '$gte', '$ne', '$or']
FILTERS
Default special query parameter converters.
import { FILTERS } from '@feathersjs/adapter-commons'
console.log(Object.keys(FILTERS))
// ['$skip', '$sort', '$limit', '$select', '$or', '$and']
Sorting
sorter
Create an in-memory sorting function from a $sort object.
import { sorter } from '@feathersjs/adapter-commons'
const sortFn = sorter({ name: 1, age: -1 })
const sorted = items.sort(sortFn)
$sort
{ [key: string]: 1 | -1 }
required
Sort specification object
result
(a: any, b: any) => number
Comparator function for Array.sort()
compare
Compare two values with proper type handling.
import { compare } from '@feathersjs/adapter-commons'
const result = compare(value1, value2)
// Returns -1, 0, or 1
Custom string comparison function
Selection
select
Create a function that picks only selected fields from results.
import { select } from '@feathersjs/adapter-commons'
const selectFn = select(params, 'id')
const filtered = selectFn(data)
Service parameters with query.$select
Additional fields to always include
Function that filters data to selected fields
Types
AdapterServiceOptions
Base options interface for all adapters.
interface AdapterServiceOptions {
id?: string
paginate?: PaginationParams
multi?: boolean | string[]
operators?: string[]
filters?: FilterSettings
events?: string[]
}
AdapterParams
Extended params interface with adapter-specific options.
interface AdapterParams<Q = AdapterQuery> extends Params<Q> {
adapter?: Partial<AdapterServiceOptions>
paginate?: PaginationParams
}
AdapterQuery
Query interface with standard filter parameters.
interface AdapterQuery extends Query {
$limit?: number
$skip?: number
$select?: string[]
$sort?: { [key: string]: 1 | -1 }
}
Pagination configuration.
interface PaginationParams {
default?: number // Default page size
max?: number // Maximum allowed page size
}
FilterSettings
Custom filter converter functions.
type FilterSettings = {
[key: string]: QueryFilter | true
}
type QueryFilter = (value: any, options: FilterQueryOptions) => any
InternalServiceMethods
Interface for hook-less internal methods (prefixed with _).
interface InternalServiceMethods<Result, Data, PatchData, Params> {
_find(params?: Params): Promise<Paginated<Result> | Result[]>
_get(id: Id, params?: Params): Promise<Result>
_create(data: Data | Data[], params?: Params): Promise<Result | Result[]>
_update(id: Id, data: Data, params?: Params): Promise<Result>
_patch(id: Id | null, data: PatchData, params?: Params): Promise<Result | Result[]>
_remove(id: Id | null, params?: Params): Promise<Result | Result[]>
}
VALIDATED Symbol
Symbol to mark queries as already validated.
import { VALIDATED } from '@feathersjs/adapter-commons'
// Mark query as validated to skip sanitization
const query = {
status: 'active',
[VALIDATED]: true
}
Example: Custom Adapter
import { AdapterBase, AdapterServiceOptions, AdapterParams } from '@feathersjs/adapter-commons'
import { Id, Paginated } from '@feathersjs/feathers'
interface MyAdapterOptions extends AdapterServiceOptions {
connection: any
}
class MyCustomAdapter<Result, Data, ServiceParams extends AdapterParams, PatchData> extends AdapterBase<
Result,
Data,
PatchData,
ServiceParams,
MyAdapterOptions
> {
async _find(params?: ServiceParams): Promise<Paginated<Result> | Result[]> {
const { query, filters } = this.filterQuery(null, params)
const { paginate } = this.getOptions(params)
// Your database query logic here
const data = await this.runQuery(query, filters)
if (paginate && paginate.default) {
const total = await this.countRecords(query)
return {
total,
data,
limit: filters.$limit,
skip: filters.$skip || 0
}
}
return data
}
async _get(id: Id, params?: ServiceParams): Promise<Result> {
// Implementation
}
async _create(data: Data | Data[], params?: ServiceParams): Promise<Result | Result[]> {
if (Array.isArray(data)) {
return Promise.all(data.map(item => this._create(item, params)))
}
// Implementation
}
async _update(id: Id, data: Data, params?: ServiceParams): Promise<Result> {
// Implementation
}
async _patch(id: Id | null, data: PatchData, params?: ServiceParams): Promise<Result | Result[]> {
if (id === null && !this.allowsMulti('patch', params)) {
throw new MethodNotAllowed('Can not patch multiple entries')
}
// Implementation
}
async _remove(id: Id | null, params?: ServiceParams): Promise<Result | Result[]> {
if (id === null && !this.allowsMulti('remove', params)) {
throw new MethodNotAllowed('Can not remove multiple entries')
}
// Implementation
}
}
// Create service
const service = new MyCustomAdapter({
connection: myConnection,
id: 'id',
paginate: { default: 10, max: 50 }
})