Skip to content

Commit

Permalink
#296 Ketcher API: Add possibility to save RXN files
Browse files Browse the repository at this point in the history
- update StructFormatter methods
- add containsReaction() method
- add getRxnAsync() method
  • Loading branch information
AndreiMazol committed Feb 8, 2021
1 parent 708a370 commit dc77efd
Show file tree
Hide file tree
Showing 9 changed files with 65 additions and 83 deletions.
13 changes: 2 additions & 11 deletions packages/ketcher-core/src/format/FormatterFactory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import {
} from '../chem'
import { StructService, StructServiceOptions } from '../infrastructure/services'
import {
StructProvider,
StructFormatter,
SupportedFormat,
FormatterFactoryOptions
Expand All @@ -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,
Expand Down Expand Up @@ -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
Expand All @@ -104,7 +96,6 @@ export class FormatterFactory {
case 'smarts':
default:
formatter = new ServerFormatter(
this.structProvider,
this.structService,
this.molfileManager,
format,
Expand Down
14 changes: 3 additions & 11 deletions packages/ketcher-core/src/format/GraphFormatter.ts
Original file line number Diff line number Diff line change
@@ -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<string> {
constructor(
private readonly structProvider: StructProvider,
private readonly graphManager: GraphManager
) {}

async getStructureAsync(): Promise<string> {
const struct = this.structProvider.struct()
return this.getStructureFromStructAsync(struct)
}
export class GraphFormatter implements StructFormatter {
constructor(private readonly graphManager: GraphManager) {}

getStructureFromStructAsync(struct: Struct): Promise<string> {
const graph = this.graphManager.toGraph(struct)
Expand Down
10 changes: 2 additions & 8 deletions packages/ketcher-core/src/format/MolfileV2000Formatter.ts
Original file line number Diff line number Diff line change
@@ -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<string> {
export class MolfileV2000Formatter implements StructFormatter {
constructor(
private readonly structProvider: StructProvider,
private readonly molfileManager: MolfileManager,
private readonly options?: MolfileParseOptions
) {}

getStructureAsync(): Promise<string> {
const struct = this.structProvider.struct()
return this.getStructureFromStructAsync(struct)
}

async getStructureFromStructAsync(struct: Struct): Promise<string> {
const stringifiedMolfile = this.molfileManager.stringify(struct)
return stringifiedMolfile
Expand Down
10 changes: 2 additions & 8 deletions packages/ketcher-core/src/format/RxnFormatter.ts
Original file line number Diff line number Diff line change
@@ -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<string> {
export class RxnFormatter implements StructFormatter {
constructor(
private readonly structProvider: StructProvider,
private readonly molfileManager: MolfileManager,
private readonly options?: MolfileParseOptions
) {}

getStructureAsync(): Promise<string> {
const struct = this.structProvider.struct()
return this.getStructureFromStructAsync(struct)
}

getStructureFromStructAsync(struct: Struct): Promise<string> {
const stringifiedMolfile = this.molfileManager.stringify(struct)
return Promise.resolve(stringifiedMolfile)
Expand Down
9 changes: 1 addition & 8 deletions packages/ketcher-core/src/format/ServerFormatter.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { MolfileManager, Struct } from '../chem'
import { getPropertiesByFormat } from './formatProperties'
import { StructProvider } from './structFormatter.types'
import {
ConvertData,
ConvertResult,
Expand All @@ -11,20 +10,14 @@ import {
} from '../infrastructure/services'
import { StructFormatter, SupportedFormat } from './structFormatter.types'

export class ServerFormatter implements StructFormatter<string> {
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<string> {
const struct = this.structProvider.struct()
return this.getStructureFromStructAsync(struct)
}

async getStructureFromStructAsync(struct: Struct): Promise<string> {
const infoResult = await this.structService.info()
if (!infoResult.isAvailable) {
Expand Down
15 changes: 2 additions & 13 deletions packages/ketcher-core/src/format/SmilesFormatter.ts
Original file line number Diff line number Diff line change
@@ -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<string> {
export class SmilesFormatter implements StructFormatter {
constructor(
private readonly structProvider: StructProvider,
private readonly smilesManager: SmilesManager,

// only for ServerFormatter
Expand All @@ -20,19 +15,13 @@ export class SmilesFormatter implements StructFormatter<string> {
private readonly options?: StructServiceOptions
) {}

getStructureAsync(): Promise<string> {
const struct = this.structProvider.struct()
return this.getStructureFromStructAsync(struct)
}

getStructureFromStructAsync(struct: Struct): Promise<string> {
const stringifiedMolfile = this.smilesManager.stringify(struct)
return Promise.resolve(stringifiedMolfile)
}

getStructureFromStringAsync(stringifiedStruct: string): Promise<Struct> {
const serverFormatter = new ServerFormatter(
this.structProvider,
this.structService,
this.molfileManager,
this.format,
Expand Down
9 changes: 2 additions & 7 deletions packages/ketcher-core/src/format/structFormatter.types.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,11 @@
import { MolfileParseOptions, Struct } from '../chem'
import { StructServiceOptions } from '../infrastructure/services'

export interface StructFormatter<TFormat = any> {
getStructureAsync: () => Promise<TFormat>
getStructureFromStructAsync: (struct: Struct) => Promise<TFormat>
export interface StructFormatter {
getStructureFromStructAsync: (struct: Struct) => Promise<string>
getStructureFromStringAsync: (stringifiedStruct: string) => Promise<Struct>
}

export interface StructProvider {
struct: () => Struct
}

export type SupportedFormat =
| 'rxn'
| 'rxnV3000'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,6 @@ class KetcherBuilder {
this.editor = editor
this.ui = tempRef.ui
this.formatterFactory = new FormatterFactory(
editor,
structService,
graphManager,
molfileManager,
Expand Down
67 changes: 51 additions & 16 deletions packages/ketcher-react/src/script/ketcher.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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'

Expand All @@ -30,6 +29,15 @@ interface UI {
loadStruct: (struct: Struct) => any
}

function getStructureAsync(
structureFormat: SupportedFormat = 'rxn',
formatterFactory: FormatterFactory,
struct: Struct
): Promise<string> {
const formatter = formatterFactory.create(structureFormat)
return formatter.getStructureFromStructAsync(struct)
}

class Ketcher {
private origin = null

Expand All @@ -40,28 +48,55 @@ class Ketcher {
private readonly formatterFactory: FormatterFactory
) {}

getStructureAsync(structureFormat: SupportedFormat = 'rxn'): Promise<string> {
const service = this.formatterFactory.create(structureFormat)
return service.getStructureAsync()
}

getSmilesAsync(isExtended: boolean = false): Promise<string> {
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<string> {
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<Graph> {
const service = this.formatterFactory.create('graph')
return service.getStructureAsync()
getGraphAsync(): Promise<string> {
return getStructureAsync(
'graph',
this.formatterFactory,
this.editor.struct()
)
}

containsReaction(): boolean {
return this.editor.struct().hasRxnArrow()
}

getRxnAsync(molfileFormat: MolfileFormat = 'v2000'): Promise<string> {
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 {
Expand Down

0 comments on commit dc77efd

Please sign in to comment.