import { Mapping, Parameters, ValueType, JSONValue, ObjectType, JSONDataValue } from './types'; import {Id} from '../shared'; import {FieldType, FormatType, JSONByteFormatType, JSONFormatType} from '../modeling'; export interface ResourceField { [key: string]: string | FieldType | FormatType | ValueType | Parameters; name: string; field: FieldType; format: JSONFormatType; } export interface RelationField extends ResourceField { relation: Id | string; mapping: ValueType; mappingParams: Parameters; } export class ResourceSchema { private readonly _fields: { [_: string]: ResourceField }; public constructor() { this._fields = {}; } addField(name: string, fieldType: 'id', formatType: JSONByteFormatType): ResourceSchema addField(name: string, fieldType: 'name', formatType: 'string'): ResourceSchema addField(name: string, fieldType: 'created', formatType: 'integer'): ResourceSchema addField(name: string, fieldType: 'size', formatType: 'integer'): ResourceSchema addField(name: string, fieldType: 'user', formatType: JSONByteFormatType): ResourceSchema addField(name: string, fieldType: 'data', formatType: JSONFormatType): ResourceSchema addField(name: string, fieldType: 'id', formatType: JSONByteFormatType, relationId: Id, mapping: Mapping): ResourceSchema addField(name: string, fieldType: 'name', formatType: 'string', relationId: Id, mapping: Mapping): ResourceSchema addField(name: string, fieldType: 'created', formatType: 'integer', relationId: Id, mapping: Mapping): ResourceSchema addField(name: string, fieldType: 'size', formatType: 'integer', relationId: Id, mapping: Mapping): ResourceSchema addField(name: string, fieldType: 'user', formatType: JSONByteFormatType, relationId: Id, mapping: Mapping): ResourceSchema addField(name: string, fieldType: 'data', formatType: JSONFormatType, relationId: Id, mapping: Mapping): ResourceSchema public addField(name: string, fieldType: FieldType, formatType: JSONFormatType, relationId?: Id, mapping?: Mapping): ResourceSchema { if (!relationId) { this.addObjectField(name, fieldType, formatType); } else { this.addRelationField(name, relationId, fieldType, formatType, mapping!); } return this; } public getField(name: string): ResourceField | undefined { return this._fields[name] ?? undefined; } private addObjectField(name: string, fieldType: FieldType, formatType: JSONFormatType) { this._fields[name] = { 'name': name, 'field': fieldType, 'format': formatType, 'mapping': 'primitive', }; } private addRelationField(name: string, relation: Id | string, fieldType: FieldType, formatType: JSONFormatType, mapping: Mapping) { this._fields[name] = { 'name': name, 'relation': relation, 'field': fieldType, 'format': formatType, 'mapping': mapping.valueType, 'mappingParams': mapping.parameters, } as RelationField; } public get object() { return { 'fields': Array.from(Object.values(this._fields)), }; } public get fields(): ResourceField[] { return Array.from(Object.values(this._fields)); } public add(schema: ResourceSchema): ResourceSchema { const newSchema = new ResourceSchema(); for (const k in schema._fields) { newSchema._fields[k] = schema._fields[k]; } for (const k in this._fields) { newSchema._fields[k] = this._fields[k]; } return newSchema; } } export type ResourceFilterOperator = 'eq' | 'ne' | 'gt' | 'ge' | 'lt' | 'le'; export interface ResourceFilterEntry { [key: string]: string | T | ResourceFilterOperator; name: string; value: T; operator: ResourceFilterOperator; } export class ResourceFilter { private readonly _filters: ResourceFilterEntry[]; public constructor() { this._filters = []; } /** @internal */ public filter(name: string, value: T, operatorType: ResourceFilterOperator): ResourceFilter { this._filters.push({ 'name': name, 'value': value, 'operator': operatorType, }); return this; } public get entries(): ResourceFilterEntry[] { return Array.from(this._filters); } } export interface ResourceOrderEntry { [key: string]: string | boolean; name: string; ascending: boolean; } export class ResourceOrder { private readonly _orders: ResourceOrderEntry[]; public constructor() { this._orders = []; } /** @internal */ public order(name: string, ascending: boolean): ResourceOrder { this._orders.push({ 'name': name, 'ascending': ascending, }); return this; } public get entries(): ResourceOrderEntry[] { return Array.from(this._orders); } } export abstract class Resource { protected _objectId: Id; protected _schema: ResourceSchema; protected _objectType: ObjectType; constructor(objectId: Id, schema: ResourceSchema, objectType: ObjectType) { this._objectId = objectId; this._schema = schema; this._objectType = objectType; } public get objectId(): Id { return this._objectId; } public get schema(): ResourceSchema { return this._schema; } public get objectType(): ObjectType { return this._objectType; } /** @internal */ public abstract toGetRequest(): { [_: string]: JSONValue }; } export class ResourceInstance extends Resource { constructor(objectId: Id, schema: ResourceSchema) { super(objectId, schema, 'instance'); } /** @internal */ public toGetRequest(): { [_: string]: JSONValue } { return { 'objectId': this.objectId, 'schema': this.schema.object, 'object': this.objectType, } } } export class ResourceSpecials extends Resource { private _filter: ResourceFilter; private _order: ResourceOrder; private _offset?: number; private _limit?: number; constructor(objectId: Id, schema: ResourceSchema) { super(objectId, schema, 'specials'); this._filter = new ResourceFilter(); this._order = new ResourceOrder(); } public get filter(): ResourceFilter { return this._filter; } public set filter(filter: ResourceFilter) { this.setFilter(filter); } public setFilter(filter: ResourceFilter): ResourceSpecials { this._filter = filter; return this; } public addFilter(name: string, value: JSONDataValue, operatorType: ResourceFilterOperator): ResourceSpecials { if (this.schema.getField(name)) { this._filter.filter(name, value, operatorType); } return this; } public get order(): ResourceOrder { return this._order; } public set order(order: ResourceOrder) { this.setOrder(order); } public setOrder(order: ResourceOrder): ResourceSpecials { this._order = order; return this; } public addOrder(name: string, ascending = true): ResourceSpecials { if (this.schema.getField(name)) { this._order.order(name, ascending); } return this; } public get offset(): number | undefined { return this._offset; } public set offset(offset: number | undefined) { this._offset = offset; } public setOffset(offset: number | undefined): ResourceSpecials { this.offset = offset; return this; } public get limit(): number | undefined { return this._limit; } public set limit(offset: number | undefined) { this._limit = offset; } public setLimit(limit: number | undefined): ResourceSpecials { this.limit = limit; return this; } /** @internal */ public toGetRequest(): { [_: string]: JSONValue } { const params: { [_: string]: JSONValue } = { 'objectId': this.objectId, 'schema': this.schema.object, 'object': this.objectType, 'filter': this._filter.entries, 'order': this._order.entries, } if (typeof this.offset !== 'undefined') { params['offset'] = this.offset; } if (typeof this.limit !== 'undefined') { params['limit'] = this.limit; } return params; } }