From dc77efdbd41c9b6fe3b1d56ef4b7a688b09d0f9e Mon Sep 17 00:00:00 2001 From: Andrei Mazol Date: Mon, 8 Feb 2021 15:57:33 +0300 Subject: [PATCH] #296 Ketcher API: Add possibility to save RXN files - update StructFormatter methods - add containsReaction() method - add getRxnAsync() method --- .../src/format/FormatterFactory.ts | 13 +--- .../ketcher-core/src/format/GraphFormatter.ts | 14 +--- .../src/format/MolfileV2000Formatter.ts | 10 +-- .../ketcher-core/src/format/RxnFormatter.ts | 10 +-- .../src/format/ServerFormatter.ts | 9 +-- .../src/format/SmilesFormatter.ts | 15 +---- .../src/format/structFormatter.types.ts | 9 +-- .../script/builders/ketcher/KetcherBuilder.ts | 1 - packages/ketcher-react/src/script/ketcher.ts | 67 ++++++++++++++----- 9 files changed, 65 insertions(+), 83 deletions(-) diff --git a/packages/ketcher-core/src/format/FormatterFactory.ts b/packages/ketcher-core/src/format/FormatterFactory.ts index 489af22cf9..b0393a7f81 100644 --- a/packages/ketcher-core/src/format/FormatterFactory.ts +++ b/packages/ketcher-core/src/format/FormatterFactory.ts @@ -6,7 +6,6 @@ import { } from '../chem' import { StructService, StructServiceOptions } from '../infrastructure/services' import { - StructProvider, StructFormatter, SupportedFormat, FormatterFactoryOptions @@ -19,7 +18,6 @@ import { SmilesFormatter } from './SmilesFormatter' export class FormatterFactory { constructor( - private readonly structProvider: StructProvider, private readonly structService: StructService, private readonly graphManager: GraphManager, private readonly molfileManager: MolfileManager, @@ -62,28 +60,22 @@ export class FormatterFactory { let formatter: StructFormatter switch (format) { case 'graph': - formatter = new GraphFormatter(this.structProvider, this.graphManager) + formatter = new GraphFormatter(this.graphManager) break case 'mol': formatter = new MolfileV2000Formatter( - this.structProvider, this.molfileManager, molfileParseOptions ) break case 'rxn': - formatter = new RxnFormatter( - this.structProvider, - this.molfileManager, - molfileParseOptions - ) + formatter = new RxnFormatter(this.molfileManager, molfileParseOptions) break case 'smiles': formatter = new SmilesFormatter( - this.structProvider, this.smilesManager, // only for ServerFormatter, because 'getStructureFromStringAsync' is delegated to it @@ -104,7 +96,6 @@ export class FormatterFactory { case 'smarts': default: formatter = new ServerFormatter( - this.structProvider, this.structService, this.molfileManager, format, diff --git a/packages/ketcher-core/src/format/GraphFormatter.ts b/packages/ketcher-core/src/format/GraphFormatter.ts index eddbfcf9e2..1dae92059c 100644 --- a/packages/ketcher-core/src/format/GraphFormatter.ts +++ b/packages/ketcher-core/src/format/GraphFormatter.ts @@ -1,16 +1,8 @@ import { GraphManager, Struct } from '../chem' -import { StructFormatter, StructProvider } from './structFormatter.types' +import { StructFormatter } from './structFormatter.types' -export class GraphFormatter implements StructFormatter { - constructor( - private readonly structProvider: StructProvider, - private readonly graphManager: GraphManager - ) {} - - async getStructureAsync(): Promise { - const struct = this.structProvider.struct() - return this.getStructureFromStructAsync(struct) - } +export class GraphFormatter implements StructFormatter { + constructor(private readonly graphManager: GraphManager) {} getStructureFromStructAsync(struct: Struct): Promise { const graph = this.graphManager.toGraph(struct) diff --git a/packages/ketcher-core/src/format/MolfileV2000Formatter.ts b/packages/ketcher-core/src/format/MolfileV2000Formatter.ts index ee0227e646..4f6fe68c2f 100644 --- a/packages/ketcher-core/src/format/MolfileV2000Formatter.ts +++ b/packages/ketcher-core/src/format/MolfileV2000Formatter.ts @@ -1,18 +1,12 @@ import { MolfileManager, MolfileParseOptions, Struct } from '../chem' -import { StructFormatter, StructProvider } from './structFormatter.types' +import { StructFormatter } from './structFormatter.types' -export class MolfileV2000Formatter implements StructFormatter { +export class MolfileV2000Formatter implements StructFormatter { constructor( - private readonly structProvider: StructProvider, private readonly molfileManager: MolfileManager, private readonly options?: MolfileParseOptions ) {} - getStructureAsync(): Promise { - const struct = this.structProvider.struct() - return this.getStructureFromStructAsync(struct) - } - async getStructureFromStructAsync(struct: Struct): Promise { const stringifiedMolfile = this.molfileManager.stringify(struct) return stringifiedMolfile diff --git a/packages/ketcher-core/src/format/RxnFormatter.ts b/packages/ketcher-core/src/format/RxnFormatter.ts index ecb325dc3a..10cd61817f 100644 --- a/packages/ketcher-core/src/format/RxnFormatter.ts +++ b/packages/ketcher-core/src/format/RxnFormatter.ts @@ -1,18 +1,12 @@ import { MolfileManager, MolfileParseOptions, Struct } from '../chem' -import { StructFormatter, StructProvider } from './structFormatter.types' +import { StructFormatter } from './structFormatter.types' -export class RxnFormatter implements StructFormatter { +export class RxnFormatter implements StructFormatter { constructor( - private readonly structProvider: StructProvider, private readonly molfileManager: MolfileManager, private readonly options?: MolfileParseOptions ) {} - getStructureAsync(): Promise { - const struct = this.structProvider.struct() - return this.getStructureFromStructAsync(struct) - } - getStructureFromStructAsync(struct: Struct): Promise { const stringifiedMolfile = this.molfileManager.stringify(struct) return Promise.resolve(stringifiedMolfile) diff --git a/packages/ketcher-core/src/format/ServerFormatter.ts b/packages/ketcher-core/src/format/ServerFormatter.ts index f073f7872e..77ed4bd5cd 100644 --- a/packages/ketcher-core/src/format/ServerFormatter.ts +++ b/packages/ketcher-core/src/format/ServerFormatter.ts @@ -1,6 +1,5 @@ import { MolfileManager, Struct } from '../chem' import { getPropertiesByFormat } from './formatProperties' -import { StructProvider } from './structFormatter.types' import { ConvertData, ConvertResult, @@ -11,20 +10,14 @@ import { } from '../infrastructure/services' import { StructFormatter, SupportedFormat } from './structFormatter.types' -export class ServerFormatter implements StructFormatter { +export class ServerFormatter implements StructFormatter { constructor( - private readonly structProvider: StructProvider, private readonly structService: StructService, private readonly molfileManager: MolfileManager, private readonly format: SupportedFormat, private readonly options?: StructServiceOptions ) {} - async getStructureAsync(): Promise { - const struct = this.structProvider.struct() - return this.getStructureFromStructAsync(struct) - } - async getStructureFromStructAsync(struct: Struct): Promise { const infoResult = await this.structService.info() if (!infoResult.isAvailable) { diff --git a/packages/ketcher-core/src/format/SmilesFormatter.ts b/packages/ketcher-core/src/format/SmilesFormatter.ts index 784dd46456..cc4ea66c70 100644 --- a/packages/ketcher-core/src/format/SmilesFormatter.ts +++ b/packages/ketcher-core/src/format/SmilesFormatter.ts @@ -1,15 +1,10 @@ import { MolfileManager, SmilesManager, Struct } from '../chem' import { StructService, StructServiceOptions } from '../infrastructure/services' import { ServerFormatter } from './ServerFormatter' -import { - StructFormatter, - StructProvider, - SupportedFormat -} from './structFormatter.types' +import { StructFormatter, SupportedFormat } from './structFormatter.types' -export class SmilesFormatter implements StructFormatter { +export class SmilesFormatter implements StructFormatter { constructor( - private readonly structProvider: StructProvider, private readonly smilesManager: SmilesManager, // only for ServerFormatter @@ -20,11 +15,6 @@ export class SmilesFormatter implements StructFormatter { private readonly options?: StructServiceOptions ) {} - getStructureAsync(): Promise { - const struct = this.structProvider.struct() - return this.getStructureFromStructAsync(struct) - } - getStructureFromStructAsync(struct: Struct): Promise { const stringifiedMolfile = this.smilesManager.stringify(struct) return Promise.resolve(stringifiedMolfile) @@ -32,7 +22,6 @@ export class SmilesFormatter implements StructFormatter { getStructureFromStringAsync(stringifiedStruct: string): Promise { const serverFormatter = new ServerFormatter( - this.structProvider, this.structService, this.molfileManager, this.format, diff --git a/packages/ketcher-core/src/format/structFormatter.types.ts b/packages/ketcher-core/src/format/structFormatter.types.ts index b9b412cc99..1fc7daa105 100644 --- a/packages/ketcher-core/src/format/structFormatter.types.ts +++ b/packages/ketcher-core/src/format/structFormatter.types.ts @@ -1,16 +1,11 @@ import { MolfileParseOptions, Struct } from '../chem' import { StructServiceOptions } from '../infrastructure/services' -export interface StructFormatter { - getStructureAsync: () => Promise - getStructureFromStructAsync: (struct: Struct) => Promise +export interface StructFormatter { + getStructureFromStructAsync: (struct: Struct) => Promise getStructureFromStringAsync: (stringifiedStruct: string) => Promise } -export interface StructProvider { - struct: () => Struct -} - export type SupportedFormat = | 'rxn' | 'rxnV3000' diff --git a/packages/ketcher-react/src/script/builders/ketcher/KetcherBuilder.ts b/packages/ketcher-react/src/script/builders/ketcher/KetcherBuilder.ts index 5e7c2a0219..55407ff356 100644 --- a/packages/ketcher-react/src/script/builders/ketcher/KetcherBuilder.ts +++ b/packages/ketcher-react/src/script/builders/ketcher/KetcherBuilder.ts @@ -114,7 +114,6 @@ class KetcherBuilder { this.editor = editor this.ui = tempRef.ui this.formatterFactory = new FormatterFactory( - editor, structService, graphManager, molfileManager, diff --git a/packages/ketcher-react/src/script/ketcher.ts b/packages/ketcher-react/src/script/ketcher.ts index dd23b67950..5b9d8c61dc 100644 --- a/packages/ketcher-react/src/script/ketcher.ts +++ b/packages/ketcher-react/src/script/ketcher.ts @@ -15,13 +15,12 @@ ***************************************************************************/ import { FormatterFactory, - Graph, StructService, - SupportedFormat + SupportedFormat, + Struct } from 'ketcher-core' import { isEqual } from 'lodash/fp' import molfile, { MolfileFormat } from './chem/molfile' -import Struct from './chem/struct' import Editor from './editor' import Render from './render' @@ -30,6 +29,15 @@ interface UI { loadStruct: (struct: Struct) => any } +function getStructureAsync( + structureFormat: SupportedFormat = 'rxn', + formatterFactory: FormatterFactory, + struct: Struct +): Promise { + const formatter = formatterFactory.create(structureFormat) + return formatter.getStructureFromStructAsync(struct) +} + class Ketcher { private origin = null @@ -40,28 +48,55 @@ class Ketcher { private readonly formatterFactory: FormatterFactory ) {} - getStructureAsync(structureFormat: SupportedFormat = 'rxn'): Promise { - const service = this.formatterFactory.create(structureFormat) - return service.getStructureAsync() - } - getSmilesAsync(isExtended: boolean = false): Promise { const format: SupportedFormat = isExtended ? 'smilesExt' : 'smiles' - - const service = this.formatterFactory.create(format) - return service.getStructureAsync() + return getStructureAsync( + format, + this.formatterFactory, + this.editor.struct() + ) } getMolfileAsync(molfileFormat: MolfileFormat = 'v2000'): Promise { + if (this.containsReaction()) { + throw Error( + 'The structure cannot be saved as *.MOL due to reaction arrrows.' + ) + } const format: SupportedFormat = molfileFormat === 'v3000' ? 'molV3000' : 'mol' - const service = this.formatterFactory.create(format) - return service.getStructureAsync() + return getStructureAsync( + format, + this.formatterFactory, + this.editor.struct() + ) } - async getGraphAsync(): Promise { - const service = this.formatterFactory.create('graph') - return service.getStructureAsync() + getGraphAsync(): Promise { + return getStructureAsync( + 'graph', + this.formatterFactory, + this.editor.struct() + ) + } + + containsReaction(): boolean { + return this.editor.struct().hasRxnArrow() + } + + getRxnAsync(molfileFormat: MolfileFormat = 'v2000'): Promise { + if (!this.containsReaction()) { + throw Error( + 'The structure cannot be saved as *.RXN: there is no reaction arrows.' + ) + } + const format: SupportedFormat = + molfileFormat === 'v3000' ? 'rxnV3000' : 'rxn' + return getStructureAsync( + format, + this.formatterFactory, + this.editor.struct() + ) } setMolecule(molString: string): void {