Skip to content
Permalink
master
Switch branches/tags

Name already in use

A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?
Go to file
 
 
Cannot retrieve contributors at this time
/* eslint-disable @typescript-eslint/no-empty-function */
/* eslint-disable @typescript-eslint/no-unused-vars */
/* eslint class-methods-use-this: 0 no-unused-vars: 0 */
/* eslint no-useless-constructor: 0 */
import { SupportedDatabasesType } from './supported-databases.type'
import { BaseProperty, BaseRecord, ParamsType } from '..'
import { NotImplementedError, Filter } from '../../utils'
import { ResourceOptions, ResourceDecorator } from '../../decorators'
import AdminJS from '../../../adminjs'
/**
* Representation of a ORM Resource in AdminJS. Visually resource is a list item in the sidebar.
* Each resource has many records and many properties.
*
* Analogy is REST resource.
*
* It is an __abstract class__ and all database adapters should implement extend it implement
* following methods:
*
* - (static) {@link BaseResource.isAdapterFor isAdapterFor()}
* - {@link BaseResource#databaseName databaseName()}
* - {@link BaseResource#name name()}
* - {@link BaseResource#id id()}
* - {@link BaseResource#properties properties()}
* - {@link BaseResource#property property()}
* - {@link BaseResource#count count()}
* - {@link BaseResource#find find()}
* - {@link BaseResource#findOne findOne()}
* - {@link BaseResource#findMany findMany()}
* - {@link BaseResource#create create()}
* - {@link BaseResource#update update()}
* - {@link BaseResource#delete delete()}
* @category Base
* @abstract
* @hideconstructor
*/
class BaseResource {
public _decorated: ResourceDecorator | null
/**
* Checks if given adapter supports resource provided by the user.
* This function has to be implemented only if you want to create your custom
* database adapter.
*
* For one time Admin Resource creation - it is not needed.
*
* @param {any} rawResource resource provided in AdminJSOptions#resources array
* @return {Boolean} if given adapter supports this resource - returns true
* @abstract
*/
static isAdapterFor(rawResource): boolean {
throw new NotImplementedError('BaseResource.isAdapterFor')
}
/**
* Creates given resource based on the raw resource object
*
* @param {Object} [resource]
*/
constructor(resource?: any) {
this._decorated = null
}
/**
* The name of the database to which resource belongs. When resource is
* a mongoose model it should be database name of the mongo database.
*
* Visually, by default, all resources are nested in sidebar under their database names.
* @return {String} database name
* @abstract
*/
databaseName(): string {
throw new NotImplementedError('BaseResource#databaseName')
}
/**
* Returns type of the database. It is used to compute sidebar icon for
* given resource. Default: 'database'
* @return {String}
*/
databaseType(): SupportedDatabasesType | string {
return 'other'
}
/**
* Each resource has to have uniq id which will be put to an URL of AdminJS routes.
* For instance in {@link Router} path for the `new` form is `/resources/{resourceId}/new`
* @return {String} uniq resource id
* @abstract
*/
id(): string {
throw new NotImplementedError('BaseResource#id')
}
/**
* returns array of all properties which belongs to resource
* @return {BaseProperty[]}
* @abstract
*/
properties(): Array<BaseProperty> {
throw new NotImplementedError('BaseResource#properties')
}
/**
* returns property object for given field
* @param {String} path path/name of the property. Take a look at
* {@link BaseProperty} to learn more about
* property paths.
* @return {BaseProperty | null}
* @abstract
*/
property(path: string): BaseProperty | null {
throw new NotImplementedError('BaseResource#property')
}
/**
* Returns number of elements for given resource by including filters
* @param {Filter} filter represents what data should be included
* @return {Promise<Number>}
* @abstract
*/
async count(filter: Filter): Promise<number> {
throw new NotImplementedError('BaseResource#count')
}
/**
* Returns actual records for given resource
*
* @param {Filter} filters what data should be included
* @param {Object} options
* @param {Number} [options.limit] how many records should be taken
* @param {Number} [options.offset] offset
* @param {Object} [options.sort] sort
* @param {Number} [options.sort.sortBy] sortable field
* @param {Number} [options.sort.direction] either asc or desc
* @return {Promise<BaseRecord[]>} list of records
* @abstract
* @example
* // filters example
* {
* name: 'Tom',
* createdAt: { from: '2019-01-01', to: '2019-01-18' }
* }
*/
async find(filter: Filter, options: {
limit?: number;
offset?: number;
sort?: {
sortBy?: string;
direction?: 'asc' | 'desc';
};
}): Promise<Array<BaseRecord>> {
throw new NotImplementedError('BaseResource#find')
}
/**
* Finds one Record in the Resource by its id
*
* @param {String} id uniq id of the Resource Record
* @return {Promise<BaseRecord> | null} record
* @abstract
*/
async findOne(id: string): Promise<BaseRecord | null> {
throw new NotImplementedError('BaseResource#findOne')
}
/**
* Finds many records based on the resource ids
*
* @param {Array<string>} list of ids to find
*
* @return {Promise<Array<BaseRecord>>} records
*/
async findMany(ids: Array<string | number>): Promise<Array<BaseRecord>> {
throw new NotImplementedError('BaseResource#findMany')
}
/**
* Builds new Record of given Resource.
*
* Each Record is an representation of the resource item. Before it can be saved,
* it has to be instantiated.
*
* This function has to be implemented if you want to create new records.
*
* @param {Record<string, any>} params
* @return {BaseRecord}
*/
build(params: Record<string, any>): BaseRecord {
return new BaseRecord(params, this)
}
/**
* Creates new record
*
* @param {Record<string, any>} params
* @return {Promise<Object>} created record converted to raw Object which
* can be used to initiate new {@link BaseRecord} instance
* @throws {ValidationError} If there are validation errors it should be thrown
* @abstract
*/
async create(params: Record<string, any>): Promise<ParamsType> {
throw new NotImplementedError('BaseResource#create')
}
/**
* Updates an the record.
*
* @param {String} id uniq id of the Resource Record
* @param {Record<string, any>} params
* @return {Promise<Object>} created record converted to raw Object which
* can be used to initiate new {@link BaseRecord} instance
* @throws {ValidationError} If there are validation errors it should be thrown
* @abstract
*/
async update(id: string, params: Record<string, any>): Promise<ParamsType> {
throw new NotImplementedError('BaseResource#update')
}
/**
* Delete given record by id
*
* @param {String | Number} id id of the Record
* @throws {ValidationError} If there are validation errors it should be thrown
* @abstract
*/
async delete(id: string): Promise<void> {
throw new NotImplementedError('BaseResource#delete')
}
/**
* Assigns given decorator to the Resource. Than it will be available under
* resource.decorate() method
*
* @param {BaseDecorator} Decorator
* @param {AdminJS} admin current instance of AdminJS
* @param {ResourceOptions} [options]
* @private
*/
assignDecorator(admin: AdminJS, options: ResourceOptions = {}): void {
this._decorated = new ResourceDecorator({ resource: this, admin, options })
}
/**
* Gets decorator object for given resource
* @return {BaseDecorator | null}
*/
decorate(): ResourceDecorator {
if (!this._decorated) {
throw new Error('resource does not have any assigned decorator yet')
}
return this._decorated
}
}
export default BaseResource