UNPKG

benchling_typescript_sdk

Version:

Typescript SDK for Benchling API

214 lines (204 loc) 7.18 kB
import { BenchlingClient } from "../BenchlingClient"; import { AppConfigItem, AppConfigType, Schema } from "../types"; export type KeyName = string; export type SchemaId = string; export type SubKeyName = string; export type FieldId = string; export type FieldDisplayName = string; export type ConfigItem = { id: string | null; name: string | null; value: any; type: AppConfigType; description: string | null; f: Record<SubKeyName, ConfigFItem>; }; export type ConfigFItem = { id: string | null; system_name: string | null; value: any; type: AppConfigType; description: string | null; displayName: string | null; }; export type SchemaTypes = Partial<Record<AppConfigType, SchemaId[]>>; export type fieldIdDisplayName = Record<FieldId, FieldDisplayName>; export class AppConfigItems { private benchling: BenchlingClient; constructor(client: BenchlingClient) { this.benchling = client; } public async getAppConfigurations(appId: string): Promise<Record<KeyName, ConfigItem>> { let appConfigurationPageGenerator = this.benchling.apps.listAppConfigurationItemsNoLimits({ appId, }); let configs: AppConfigItem[] = []; // print type of appConfigurationPageGenerator for await (const page of appConfigurationPageGenerator) { for (const item of page) { configs.push(item); } } let object = this.compileAppConfigItems(configs); return object; } private async collectSchemas( schemaTypes: Partial<Record<AppConfigType, string[]>> ): Promise<Schema[]> { let schemas: Schema[] = []; for (const [t, schemaIds] of Object.entries(schemaTypes)) { let type = t as AppConfigType; if (schemaIds.length > 0) { if (type === "entity_schema") { for (const schemaId of schemaIds) { let schema = await this.benchling.schemas.getEntitySchema(schemaId); schemas.push(schema); } } else if (type === "container_schema") { for (const schemaId of schemaIds) { let schema = await this.benchling.schemas.getContainerSchema(schemaId); schemas.push(schema); } } else if (type === "location_schema") { for (const schemaId of schemaIds) { let schema = await this.benchling.schemas.getLocationSchema(schemaId); schemas.push(schema); } } else if (type === "box_schema") { for (const schemaId of schemaIds) { let schema = await this.benchling.schemas.getBoxSchema(schemaId); schemas.push(schema); } } else if (type === "plate_schema") { for (const schemaId of schemaIds) { let schema = await this.benchling.schemas.getPlateSchema(schemaId); schemas.push(schema); } } else if (type === "result_schema") { for (const schemaId of schemaIds) { let schema = await this.benchling.schemas.getAssayResultSchema(schemaId); schemas.push(schema); } } else if (type === "run_schema") { for (const schemaId of schemaIds) { let schema = await this.benchling.schemas.getAssayRunSchema(schemaId); schemas.push(schema); } } else { console.warn(`Unknown schema type: ${type}`); } } } return schemas; } private async compileAppConfigItems( appConfigItems: AppConfigItem[] ): Promise<Record<string, ConfigItem>> { let schemaTypes: SchemaTypes = {}; let schemaKeyNameFields: Record<KeyName, FieldId[]> = {}; let schemaKeyNameIds: Record<KeyName, SchemaId> = {}; let compiledConfigs = AppConfigItems.preCompileConfigItems( appConfigItems, schemaTypes, schemaKeyNameFields, schemaKeyNameIds ); let fieldIdDisplayNames: Record<FieldId, string> = {}; // Benchling returns the SYSTEM_NAMES of fields but the API requires DISPLAY_NAMES of fields // so I need to look up the schemas themselves for fucks sake let schemas: Schema[] = await this.collectSchemas(schemaTypes); for (const schema of schemas) { if (!schema.fieldDefinitions) { continue; } for (const fieldDef of schema.fieldDefinitions) { if (fieldDef.id && fieldDef.name) { fieldIdDisplayNames[fieldDef.id] = fieldDef.displayName || fieldDef.name; } } } for (const [key, configItem] of Object.entries(compiledConfigs)) { if (configItem.f) { for (const [subKey, field] of Object.entries(configItem.f)) { field.displayName = field.id ? fieldIdDisplayNames[field.id] : null; } } } return compiledConfigs; } static preCompileConfigItems( appConfigItems: AppConfigItem[], schemaTypes: SchemaTypes, // mutates schemaKeyNameFields: Record<KeyName, FieldId[]>, // mutates schemaKeyNameIds: Record<KeyName, SchemaId> // mutates ): Record<KeyName, ConfigItem> { // sort appConfigItems by path length let res: Record<KeyName, ConfigItem> = {}; // load single paths first let singlePaths = appConfigItems.filter((item) => item.path && item.path.length === 1); // load nested paths second. let nestedPaths = appConfigItems.filter((item) => item.path && item.path.length === 2); // initiate schema field definitions for (const item of singlePaths) { let { id, value, type, name, description, path } = AppConfigItems.getItemAttributes(item); res[path[0]] = { id, name, value, type, description, f: {} }; if (!id) { continue; } schemaKeyNameIds[path[0]] = id; if (!schemaTypes[type]) { schemaTypes[type] = [id]; } else { schemaTypes[type].push(id); } } for (const item of nestedPaths) { let { id, value, type, name, description, path } = AppConfigItems.getItemAttributes(item); res[path[0]].f[path[1]] = { id, system_name: name, value, description, type, displayName: null, // must look up schema to get the display names }; if (!id) { continue; } if (!schemaKeyNameFields[path[0]]) { schemaKeyNameFields[path[0]] = [id]; } else { schemaKeyNameFields[path[0]].push(id); } } return res; } static getItemAttributes(item: AppConfigItem): { id: string | null; name: string | null; value: any; description: string | null; type: AppConfigType; path: string[]; } { let id: string | null = null; let name: string | null = null; let value: any; let description: string | null = null; let type = item.type as AppConfigType; let path = item.path || []; if ("description" in item) { description = item.description || null; } if ("linkedResource" in item) { if (item.linkedResource && "id" in item.linkedResource) { id = item.linkedResource.id || null; name = item.linkedResource.name || null; } } if ("value" in item) { value = item.value || null; } return { id, name, value, description, type, path }; } }