Skip to content

Commit

Permalink
feat(typescript): Improve adapter typings (#2605)
Browse files Browse the repository at this point in the history
  • Loading branch information
daffl committed Apr 23, 2022
1 parent 77d8fda commit 3b2ca0a
Show file tree
Hide file tree
Showing 16 changed files with 402 additions and 223 deletions.
123 changes: 123 additions & 0 deletions packages/adapter-commons/src/declarations.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
import { Query, Params, Paginated, Id, NullableId } from '@feathersjs/feathers';

export type FilterSettings = string[]|{
[key: string]: (value: any, options: any) => any
}

export interface PaginationOptions {
default?: number;
max?: number;
}

export type PaginationParams = false|PaginationOptions;

export type FilterQueryOptions = {
filters?: FilterSettings;
operators?: string[];
paginate?: PaginationParams;
}

export interface AdapterServiceOptions {
events?: string[];
multi?: boolean|string[];
id?: string;
paginate?: PaginationOptions
/**
* @deprecated renamed to `allow`.
*/
whitelist?: string[];
allow?: string[];
filters?: string[];
}

export interface AdapterOptions<M = any> extends Pick<AdapterServiceOptions, 'multi'|'allow'|'paginate'> {
Model?: M;
}

export interface AdapterParams<Q = Query, M = any> extends Params<Q> {
adapter?: Partial<AdapterOptions<M>>;
paginate?: PaginationParams;
}

/**
* Hook-less (internal) service methods. Directly call database adapter service methods
* without running any service-level hooks. This can be useful if you need the raw data
* from the service and don't want to trigger any of its hooks.
*
* Important: These methods are only available internally on the server, not on the client
* side and only for the Feathers database adapters.
*
* These methods do not trigger events.
*
* @see {@link https://docs.feathersjs.com/guides/migrating.html#hook-less-service-methods}
*/
export interface InternalServiceMethods<T = any, D = Partial<T>, P extends AdapterParams = AdapterParams> {
/**
* Retrieve all resources from this service, skipping any service-level hooks.
*
* @param params - Service call parameters {@link Params}
* @see {@link HookLessServiceMethods}
* @see {@link https://docs.feathersjs.com/api/services.html#find-params|Feathers API Documentation: .find(params)}
*/
_find (_params?: P & { paginate?: PaginationOptions }): Promise<Paginated<T>>;
_find (_params?: P & { paginate: false }): Promise<T[]>;
_find (params?: P): Promise<T | T[] | Paginated<T>>;

/**
* Retrieve a single resource matching the given ID, skipping any service-level hooks.
*
* @param id - ID of the resource to locate
* @param params - Service call parameters {@link Params}
* @see {@link HookLessServiceMethods}
* @see {@link https://docs.feathersjs.com/api/services.html#get-id-params|Feathers API Documentation: .get(id, params)}
*/
_get (id: Id, params?: P): Promise<T>;

/**
* Create a new resource for this service, skipping any service-level hooks.
*
* @param data - Data to insert into this service.
* @param params - Service call parameters {@link Params}
* @see {@link HookLessServiceMethods}
* @see {@link https://docs.feathersjs.com/api/services.html#create-data-params|Feathers API Documentation: .create(data, params)}
*/
_create (data: Partial<D>, params?: P): Promise<T>;
_create (data: Partial<D>[], params?: P): Promise<T[]>;
_create (data: Partial<D>|Partial<D>[], params?: P): Promise<T|T[]>;

/**
* Replace any resources matching the given ID with the given data, skipping any service-level hooks.
*
* @param id - ID of the resource to be updated
* @param data - Data to be put in place of the current resource.
* @param params - Service call parameters {@link Params}
* @see {@link HookLessServiceMethods}
* @see {@link https://docs.feathersjs.com/api/services.html#update-id-data-params|Feathers API Documentation: .update(id, data, params)}
*/
_update (id: Id, data: D, params?: P): Promise<T>;

/**
* Merge any resources matching the given ID with the given data, skipping any service-level hooks.
*
* @param id - ID of the resource to be patched
* @param data - Data to merge with the current resource.
* @param params - Service call parameters {@link Params}
* @see {@link HookLessServiceMethods}
* @see {@link https://docs.feathersjs.com/api/services.html#patch-id-data-params|Feathers API Documentation: .patch(id, data, params)}
*/
_patch (id: null, data: Partial<D>, params?: P): Promise<T[]>;
_patch (id: Id, data: Partial<D>, params?: P): Promise<T>;
_patch (id: NullableId, data: Partial<D>, params?: P): Promise<T|T[]>;

/**
* Remove resources matching the given ID from the this service, skipping any service-level hooks.
*
* @param id - ID of the resource to be removed
* @param params - Service call parameters {@link Params}
* @see {@link HookLessServiceMethods}
* @see {@link https://docs.feathersjs.com/api/services.html#remove-id-params|Feathers API Documentation: .remove(id, params)}
*/
_remove (id: null, params?: P): Promise<T[]>;
_remove (id: Id, params?: P): Promise<T>;
_remove (id: NullableId, params?: P): Promise<T|T[]>;
}
25 changes: 13 additions & 12 deletions packages/adapter-commons/src/filter-query.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import { _ } from '@feathersjs/commons';
import { BadRequest } from '@feathersjs/errors';
import { Query } from '@feathersjs/feathers';
import { FilterQueryOptions, FilterSettings } from './declarations';

function parse (number: any) {
if (typeof number !== 'undefined') {
Expand Down Expand Up @@ -37,7 +39,7 @@ function convertSort (sort: any) {
}, {} as { [key: string]: number });
}

function cleanQuery (query: any, operators: any, filters: any): any {
function cleanQuery (query: Query, operators: any, filters: any): any {
if (Array.isArray(query)) {
return query.map(value => cleanQuery(value, operators, filters));
} else if (_.isObject(query) && query.constructor === {}.constructor) {
Expand Down Expand Up @@ -68,7 +70,7 @@ function cleanQuery (query: any, operators: any, filters: any): any {
return query;
}

function assignFilters (object: any, query: any, filters: any, options: any) {
function assignFilters (object: any, query: Query, filters: FilterSettings, options: any): { [key: string]: any } {
if (Array.isArray(filters)) {
_.each(filters, (key) => {
if (query[key] !== undefined) {
Expand All @@ -88,7 +90,7 @@ function assignFilters (object: any, query: any, filters: any, options: any) {
return object;
}

export const FILTERS = {
export const FILTERS: FilterSettings = {
$sort: (value: any) => convertSort(value),
$limit: (value: any, options: any) => getLimit(parse(value), options.paginate),
$skip: (value: any) => parse(value),
Expand All @@ -100,17 +102,16 @@ export const OPERATORS = ['$in', '$nin', '$lt', '$lte', '$gt', '$gte', '$ne', '$
// Converts Feathers special query parameters and pagination settings
// and returns them separately a `filters` and the rest of the query
// as `query`
export function filterQuery (query: any, options: any = {}) {
export function filterQuery (query: Query, options: FilterQueryOptions = {}) {
const {
filters: additionalFilters = {},
filters: additionalFilters = [],
operators: additionalOperators = []
} = options;
const result: { [key: string]: any } = {};
const baseFilters = assignFilters({}, query, FILTERS, options);
const filters = assignFilters(baseFilters, query, additionalFilters, options);

result.filters = assignFilters({}, query, FILTERS, options);
result.filters = assignFilters(result.filters, query, additionalFilters, options);

result.query = cleanQuery(query, OPERATORS.concat(additionalOperators), result.filters);

return result;
return {
filters,
query: cleanQuery(query, OPERATORS.concat(additionalOperators), filters) as Query
}
}
6 changes: 4 additions & 2 deletions packages/adapter-commons/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
import { _ } from '@feathersjs/commons';
import { Params } from '@feathersjs/feathers';

export { AdapterService, InternalServiceMethods, ServiceOptions, AdapterParams } from './service';
export * from './declarations';
export * from './service';
export { filterQuery, FILTERS, OPERATORS } from './filter-query';
export * from './sort';

// Return a function that filters a result object or array
// and picks only the fields passed as `params.query.$select`
// and additional `otherFields`
export function select (params: any, ...otherFields: string[]) {
export function select (params: Params, ...otherFields: string[]) {
const queryFields: string[] | undefined = params?.query?.$select;

if (!queryFields) {
Expand Down

0 comments on commit 3b2ca0a

Please sign in to comment.