diff --git a/packages/agent/src/routes/capabilities.ts b/packages/agent/src/routes/capabilities.ts index 61a499142a..cd1eaa94fc 100644 --- a/packages/agent/src/routes/capabilities.ts +++ b/packages/agent/src/routes/capabilities.ts @@ -37,29 +37,8 @@ export default class Capabilities extends BaseRoute { agentCapabilities: { canUseProjectionOnGetOne: true, }, - collections: - collections?.map(collection => ({ - name: collection.name, - fields: Object.entries(collection.schema.fields) - .map(([fieldName, field]) => { - return field.type === 'Column' - ? { - name: fieldName, - type: field.columnType, - operators: [...field.filterOperators].map(this.pascalCaseToSnakeCase), - } - : null; - }) - .filter(Boolean), - })) ?? [], + collections: collections?.map(collection => collection.capabilities) ?? [], }; context.response.status = HttpCode.Ok; } - - private pascalCaseToSnakeCase(str: string): string { - return str - .split(/\.?(?=[A-Z])/) - .join('_') - .toLowerCase(); - } } diff --git a/packages/datasource-customizer/src/decorators/operators-equivalence/collection.ts b/packages/datasource-customizer/src/decorators/operators-equivalence/collection.ts index a02ca7d0e5..e54029cc32 100644 --- a/packages/datasource-customizer/src/decorators/operators-equivalence/collection.ts +++ b/packages/datasource-customizer/src/decorators/operators-equivalence/collection.ts @@ -1,5 +1,6 @@ import { Caller, + CollectionCapabilities, CollectionDecorator, CollectionSchema, CollectionUtils, @@ -59,4 +60,27 @@ export default class OperatorsEquivalenceCollectionDecorator extends CollectionD }), }); } + + private pascalCaseToSnakeCase(str: string): string { + return str + .split(/\.?(?=[A-Z])/) + .join('_') + .toLowerCase(); + } + + override refineCapabilities(capabilities: CollectionCapabilities): CollectionCapabilities { + const fields = Object.entries(this.schema.fields) + .map(([fieldName, field]) => { + return field.type === 'Column' + ? { + name: fieldName, + type: field.columnType, + operators: [...field.filterOperators].map(this.pascalCaseToSnakeCase), + } + : null; + }) + .filter(Boolean); + + return { ...capabilities, fields }; + } } diff --git a/packages/datasource-toolkit/src/base-collection.ts b/packages/datasource-toolkit/src/base-collection.ts index cb66e73bf6..7b8b896871 100644 --- a/packages/datasource-toolkit/src/base-collection.ts +++ b/packages/datasource-toolkit/src/base-collection.ts @@ -31,6 +31,13 @@ export default abstract class BaseCollection implements Collection { }; } + get capabilities() { + return { + name: this.name, + fields: [], + }; + } + protected addAction(name: string, schema: ActionSchema): void { const action = this.schema.actions[name]; diff --git a/packages/datasource-toolkit/src/decorators/collection-decorator.ts b/packages/datasource-toolkit/src/decorators/collection-decorator.ts index 319e87c0f8..52b4c1f498 100644 --- a/packages/datasource-toolkit/src/decorators/collection-decorator.ts +++ b/packages/datasource-toolkit/src/decorators/collection-decorator.ts @@ -1,5 +1,6 @@ import { ActionFormElement, ActionResult } from '../interfaces/action'; import { Caller } from '../interfaces/caller'; +import { CollectionCapabilities } from '../interfaces/capabilities'; import { Chart } from '../interfaces/chart'; import { Collection, DataSource, GetFormMetas } from '../interfaces/collection'; import Aggregation, { AggregateResult } from '../interfaces/query/aggregation'; @@ -14,6 +15,7 @@ export default class CollectionDecorator implements Collection { protected childCollection: Collection; private lastSchema: CollectionSchema; + private lastCapabilities: CollectionCapabilities; get nativeDriver(): unknown { return this.childCollection.nativeDriver; @@ -33,6 +35,15 @@ export default class CollectionDecorator implements Collection { return this.childCollection.name; } + get capabilities(): CollectionCapabilities { + if (!this.lastCapabilities) { + const { capabilities } = this.childCollection; + this.lastCapabilities = this.refineCapabilities(capabilities); + } + + return this.lastCapabilities; + } + constructor(childCollection: Collection, dataSource: DataSource) { this.childCollection = childCollection; this.dataSource = dataSource; @@ -128,4 +139,8 @@ export default class CollectionDecorator implements Collection { protected refineSchema(subSchema: CollectionSchema): CollectionSchema { return subSchema; } + + protected refineCapabilities(capabilities: CollectionCapabilities): CollectionCapabilities { + return capabilities; + } } diff --git a/packages/datasource-toolkit/src/index.ts b/packages/datasource-toolkit/src/index.ts index 412c3d8f58..f3a5b116b2 100644 --- a/packages/datasource-toolkit/src/index.ts +++ b/packages/datasource-toolkit/src/index.ts @@ -29,6 +29,7 @@ export { default as SortFactory } from './interfaces/query/sort/factory'; export * from './interfaces/action'; export * from './interfaces/caller'; +export * from './interfaces/capabilities'; export * from './interfaces/chart'; export * from './interfaces/collection'; export * from './interfaces/query/aggregation'; diff --git a/packages/datasource-toolkit/src/interfaces/capabilities.ts b/packages/datasource-toolkit/src/interfaces/capabilities.ts new file mode 100644 index 0000000000..dc2819c54c --- /dev/null +++ b/packages/datasource-toolkit/src/interfaces/capabilities.ts @@ -0,0 +1,12 @@ +import { ColumnType } from './schema'; + +export type FieldCapabilities = { + name: string; + type: ColumnType; + operators: string[]; +}; + +export type CollectionCapabilities = { + name: string; + fields: FieldCapabilities[]; +}; diff --git a/packages/datasource-toolkit/src/interfaces/collection.ts b/packages/datasource-toolkit/src/interfaces/collection.ts index 3afa2a457f..d6bcb5c7dd 100644 --- a/packages/datasource-toolkit/src/interfaces/collection.ts +++ b/packages/datasource-toolkit/src/interfaces/collection.ts @@ -1,5 +1,6 @@ import { ActionFormElement, ActionResult } from './action'; import { Caller } from './caller'; +import { CollectionCapabilities } from './capabilities'; import { Chart } from './chart'; import Aggregation, { AggregateResult } from './query/aggregation'; import PaginatedFilter from './query/filter/paginated'; @@ -35,6 +36,7 @@ export interface Collection { get dataSource(): DataSource; get name(): string; get schema(): CollectionSchema; + get capabilities(): CollectionCapabilities; execute( caller: Caller, diff --git a/packages/datasource-toolkit/test/__factories__/collection.ts b/packages/datasource-toolkit/test/__factories__/collection.ts index f48da5727f..64b5f70ac7 100644 --- a/packages/datasource-toolkit/test/__factories__/collection.ts +++ b/packages/datasource-toolkit/test/__factories__/collection.ts @@ -28,6 +28,7 @@ export default CollectionFactory.define(() => ({ dataSource: null, name: 'a collection', schema: collectionSchemaFactory.build(), + capabilities: { name: 'a collection', fields: [] }, execute: jest.fn(), getForm: jest.fn(), renderChart: jest.fn(),