Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
170 changes: 4 additions & 166 deletions cqp-api/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,187 +1,25 @@
import java.net.HttpURLConnection
import kotlin.io.encoding.Base64
import kotlin.io.encoding.ExperimentalEncodingApi

plugins {
`java-library`
`maven-publish`
signing
id("com.diffplug.spotless") version "7.0.2"
id("com.quantori.cqp-build")
}

group = "com.quantori"
description = "Chem query platform. Compound quick search"
version = "0.0.10"
description = "Chem query platform. Storage API"
version = "0.0.11"

repositories {
mavenLocal()
mavenCentral()
}

java {
toolchain {
languageVersion = JavaLanguageVersion.of(17)
}
withSourcesJar()
withJavadocJar()
}

publishing {
publications {
create<MavenPublication>("mavenJava") {
from(components["java"])

pom {
artifactId = "cqp-api"
name = project.name
description = project.description
packaging = "jar"
url = "https://github.com/quantori/chem-query-platform"

licenses {
license {
name = "The Apache License, Version 2.0"
url = "https://www.apache.org/licenses/LICENSE-2.0.txt"
}
}

developers {
developer {
id = "artem.chukin"
name = "Artem Chukin"
email = "artem.chukin@quantori.com"
}
developer {
id = "dmitriy gusev"
name = "Dmitriy Gusev"
email = "dmitriy.gusev@quantori.com"
}

developer {
id = "valeriy burmistrov"
name = "Valeriy Burmistrov"
email = "valeriy.burmistrov@quantori.com"
}

developer {
id = "boris sukhodoev"
name = "Boris Sukhodoev"
email = "boris.sukhodoev@quantori.com"
}
}

scm {
connection = "scm:git:git://github.com/quantori/chem-query-platform.git"
developerConnection = "scm:git:ssh://github.com/quantori/chem-query-platform.git"
url = "https://github.com/quantori/chem-query-platform"
}
}
}
}
repositories {
maven {
name = "localStaging"
// change URLs to point to your repos, e.g. http://my.org/repo
val releasesRepoUrl = uri(layout.buildDirectory.dir("repos/releases"))
val snapshotsRepoUrl = uri(layout.buildDirectory.dir("repos/snapshots"))
url = if (version.toString().endsWith("SNAPSHOT")) snapshotsRepoUrl else releasesRepoUrl
}
}
}

tasks.test {
useJUnitPlatform()
testLogging {
events("passed", "skipped", "failed")
}
}

artifacts {
archives(tasks.named("javadocJar"))
archives(tasks.named("sourcesJar"))
}

signing {
setRequired {
!version.toString().endsWith("SNAPSHOT") && gradle.taskGraph.hasTask("publish")
}
val signingSecretKey = findProperty("signing.secretKey") as String? ?: System.getenv("GPG_SIGNING_SECRET_KEY")
val signingPassword = findProperty("signing.password") as String? ?: System.getenv("GPG_SIGNING_PASSWORD")

useInMemoryPgpKeys(signingSecretKey, signingPassword)
sign(publishing.publications["mavenJava"])
sign(configurations.archives.get())
}

// Fix Javadoc warnings on JDK 9+ (optional but recommended)
if (JavaVersion.current().isJava9Compatible) {
tasks.withType<Javadoc>().configureEach {
(options as StandardJavadocDocletOptions).addStringOption("Xdoclint:none", "-quiet")
(options as StandardJavadocDocletOptions).addBooleanOption("html5", true)
}
}

@OptIn(ExperimentalEncodingApi::class)
fun String.toBase64(): String {
return Base64.encode(this.toByteArray(Charsets.UTF_8))
}

val publishToLocalStaging = tasks.getByName("publishMavenJavaPublicationToLocalStagingRepository")

publishToLocalStaging.outputs.dir(layout.buildDirectory.dir("repos/releases"))

val zipBundle by tasks.registering(Zip::class) {
archiveFileName = "central-bundle.zip"
destinationDirectory = project.layout.buildDirectory.dir("distributions")
inputs.files(publishToLocalStaging.outputs.files)
from(publishToLocalStaging.outputs.files.files)
}

val uploadToMavenCentral by tasks.registering {
val url = uri("https://central.sonatype.com/api/v1/publisher/upload").toURL()
val boundary = "----WebKitFormBoundary7MA4YWxkTrZu0gW"
inputs.file(zipBundle.map { it.archiveFile }.get())
doLast {
val file = zipBundle.get().archiveFile.get().asFile
val mavenCentralUsername =
findProperty("mavenCentralUsername") as String? ?: System.getenv("MAVEN_CENTRAL_USERNAME")
val mavenCentralPassword =
findProperty("mavenCentralPassword") as String? ?: System.getenv("MAVEN_CENTRAL_PASSWORD")
val token = "$mavenCentralUsername:$mavenCentralPassword\n".toBase64()

val connection = (url.openConnection() as HttpURLConnection).apply {
requestMethod = "POST"
doOutput = true
setRequestProperty("Authorization", "Bearer $token")
setRequestProperty("Content-Type", "multipart/form-data; boundary=$boundary")
}

val outputStream = connection.outputStream
outputStream.bufferedWriter().use { writer ->
writer.append("--$boundary\r\n")
writer.append("Content-Disposition: form-data; name=\"bundle\"; filename=\"${file.name}\"\r\n")
writer.append("Content-Type: application/octet-stream\r\n\r\n")
writer.flush()

file.inputStream().use { it.copyTo(outputStream) }

writer.append("\r\n--$boundary--\r\n")
writer.flush()
}

val responseCode = connection.responseCode
println("Response Code: $responseCode")
println("Response Message: ${connection.inputStream.bufferedReader().readText()}")
}
}

dependencies {
implementation("commons-codec:commons-codec:1.15")
compileOnly(libs.jackson)

implementation(libs.javax.validation)
implementation(libs.bundles.indigo)
implementation(libs.common.text)
compileOnly(libs.jackson)

compileOnly(libs.lombok)
annotationProcessor(libs.lombok)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
package com.quantori.cqp.api;

import static org.junit.Assert.assertTrue;

import com.epam.indigo.Indigo;
import com.quantori.cqp.api.indigo.IndigoMatcher;
import com.quantori.cqp.api.indigo.IndigoProvider;
import com.quantori.cqp.api.model.ExactParams;
import com.quantori.cqp.api.model.SubstructureParams;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;

class ProcessChiralStructuresTest {

private final IndigoProvider indigoProvider = new IndigoProvider(100, 5);

@ParameterizedTest
@ValueSource(strings = {
"C1C=CC=C2C=CC=CC=12",
"N1([C@@]2(SC(=N1)C(=O)C)N(N=C(c1ccc(cc1)Br)CC2)c1ccccc1)c1c(cc(cc1)Cl)Cl",
"""
X-17641
MACCS-II09195910443D 1 0.00000 0.00000 0
MOE2004 3D
38 42 0 0 0 0 999 V2000 \s
9.7920 2.1040 0.0000 C 0 0 0 0 0
4.2870 7.1000 0.0000 C 0 0 0 0 0
8.5870 7.0150 0.0000 C 0 0 0 0 0
7.3550 2.1040 0.0000 N 0 0 0 0 0
7.3550 4.9100 0.0000 C 0 0 0 0 0
8.5660 4.2090 0.0000 C 0 0 0 0 0
9.7920 6.3200 0.0000 C 0 0 0 0 0
8.5660 8.4170 0.0000 O 0 0 0 0 0
8.5660 0.0070 0.0000 N 0 0 0 0 0
8.5660 2.8130 0.0000 C 0 0 2 0 0
7.3550 9.1050 0.0000 C 0 0 0 0 0
12.2010 2.1040 0.0000 O 0 0 0 0 0
0.7160 3.5140 0.0000 C 0 0 0 0 0
6.0370 0.2620 0.0000 S 0 0 0 0 0
4.2020 4.7400 0.0000 F 0 0 0 0 0
2.7850 4.7400 0.0000 C 0 0 0 0 0
11.0040 0.0000 0.0000 C 0 0 0 0 0
11.0040 4.2090 0.0000 O 0 0 0 0 0
5.5900 3.8690 0.0000 O 0 0 0 0 0
5.0160 9.2460 0.0000 C 0 0 0 0 0
2.0830 5.9520 0.0000 C 0 0 0 0 0
5.6970 7.0850 0.0000 O 0 0 0 0 0
7.3550 6.2990 0.0000 C 0 0 0 0 0
9.7920 4.9100 0.0000 C 0 0 0 0 0
3.8690 8.4250 0.0000 C 0 0 0 0 0
0.0140 2.3030 0.0000 Cl 0 0 0 0 0
6.0370 2.5300 0.0000 C 0 0 0 0 0
3.8050 1.4030 0.0000 C 0 0 0 0 0
6.1570 8.3960 0.0000 C 0 0 0 0 0
2.0830 3.5290 0.0000 C 0 0 0 0 0
5.2010 1.4030 0.0000 C 0 0 0 0 0
9.7920 0.6870 0.0000 C 0 0 0 0 0
13.4130 2.8060 0.0000 C 0 0 0 0 0
11.0040 2.8060 0.0000 C 0 0 0 0 0
0.0000 4.7400 0.0000 C 0 0 0 0 0
7.3550 0.6870 0.0000 C 0 0 0 0 0
0.7160 5.9590 0.0000 C 0 0 0 0 0
7.3550 10.5010 0.0000 O 0 0 0 0 0
4 36 1 0 0 0
4 27 1 0 0 0
4 10 1 0 0 0
36 9 2 0 0 0
36 14 1 0 0 0
1 10 1 0 0 0
1 32 2 0 0 0
1 34 1 0 0 0
27 31 1 0 0 0
27 19 2 0 0 0
31 14 1 0 0 0
31 28 2 0 0 0
9 32 1 0 0 0
10 6 1 0 0 0
32 17 1 0 0 0
28 30 1 0 0 0
30 13 2 0 0 0
30 16 1 0 0 0
11 29 1 0 0 0
11 8 1 0 0 0
11 38 2 0 0 0
34 18 2 0 0 0
34 12 1 0 0 0
29 22 1 0 0 0
29 20 2 0 0 0
6 24 2 0 0 0
6 5 1 0 0 0
8 3 1 0 0 0
22 2 1 0 0 0
13 26 1 0 0 0
13 35 1 0 0 0
16 15 1 0 0 0
16 21 2 0 0 0
20 25 1 0 0 0
2 25 2 0 0 0
24 7 1 0 0 0
5 23 2 0 0 0
3 23 1 0 0 0
3 7 2 0 0 0
12 33 1 0 0 0
37 21 1 0 0 0
37 35 2 0 0 0
M END
"""
})
void test_exact_match(String structure) {
var indigoObject = new Indigo().loadMolecule(structure);
var exactParams = ExactParams.builder().searchQuery(structure).build();
assertTrue(new IndigoMatcher(indigoProvider).isExactMatch(indigoObject.serialize(), exactParams));
}

@ParameterizedTest
@ValueSource(strings = {
"N1([C@@](C=C(C1=O)Nc1ccc(I)cc1)(C(=O)OCC)C)c1ccc(cc1)I",
"N1([C@@]2(SC(=N1)C(=O)C)N(N=C(c1ccc(cc1)Br)CC2)c1ccccc1)c1c(cc(cc1)Cl)Cl",
"c1(c(c2c([nH]c1=O)ccc(c2)Cl)c1ccccc1)C1=NN(C(Nc2ccccc2)=S)[C@H](C1)c1ccc(cc1)OC",
"c1(c(c2c([nH]c1=O)ccc(c2)Cl)c1ccccc1)C1=NN([C@H](C1)c1cc(c(cc1)OC)OC)C(=O)CCC(=O)O",
"N1(N=C(c2c(c3c(nc2C)ccc(c3)Br)c2ccccc2)C[C@H]1c1ccc(cc1)C)C(=O)CCC(=O)O",
"c12n(c(c3c(n1c(nn2)SCC(c1ccc(cc1)Cl)=O)sc1c3CC[C@H](C1)C(C)(C)C)=O)c1c(C)cccc1",
"c12n([C@H](C(F)(F)F)C[C@H](N2)c2ccc(cc2)Br)ncc1C(Nc1cc(c(c(c1)OC)OC)OC)=O"
})
void test_sub_search(String structure) {
var indigoObject = new Indigo().loadMolecule(structure);
var substructureParams = SubstructureParams.builder().searchQuery(structure).heteroatoms(false).build();
assertTrue(new IndigoMatcher(indigoProvider).isSubstructureMatch(indigoObject.serialize(), substructureParams));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
package com.quantori.cqp.api;

import com.quantori.cqp.api.indigo.IndigoMatcher;
import com.quantori.cqp.api.indigo.IndigoProvider;
import com.quantori.cqp.api.model.SubstructureParams;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;

import java.util.stream.Stream;

class ProcessStructureTest {

private static Stream<Arguments> molecules() {
return Stream.of(
Arguments.of("C1C=CC=C2CCC=12>>C1CCC1",
"[NH2:1][C:2]1=[CH:3][CH:4]=[C:5]([C:8]2=[CH:9][N:10]=[C:11]([C:13]3([CH2:14][CH2:15][CH2:16]3)[O:17]"
+ "[CH2:18][C:19](=[O:20])[O:21]C)[S:12]2)[CH:6]=[CH:7]1.[CH:23]1([CH2:24][C:25]2=[C:26]1[CH:27]="
+ "[CH:28][CH:29]=[CH:30]2)[C:31](=[O:32])O.CN1CCOCC1.O.ON1N=NC2=C1C=CC=C2.Cl.C(C)N=C=NCCCN(C)C>CN(C=O)"
+ "C>[C:25]12=[CH:30][CH:29]=[CH:28][CH:27]=[C:26]1[CH:23]([C:31](=[O:32])[NH:1][C:2]1=[CH:3][CH:4]"
+ "=[C:5]([C:8]3=[CH:9][N:10]=[C:11]([C:13]4([CH2:14][CH2:15][CH2:16]4)[O:17][CH2:18][C:19](=[O:20])"
+ "[OH:21])[S:12]3)[CH:6]=[CH:7]1)[CH2:24]2 |f:3.4,5.6|"),

Arguments.of("C1C=CC=C2CCC=12>>C1CCC1",
"[NH2:1][C:2]1=[CH:3][CH:4]=[C:5]([C:8]2=[CH:9][N:10]=[C:11]([C:13]3([CH2:14][CH2:15][CH2:16]3)[O:17]"
+ "[CH2:18][C:19](=[O:20])[O:21]C)[S:12]2)[CH:6]=[CH:7]1.[CH:23]1([CH2:24][C:25]2=[C:26]1[CH:27]="
+ "[CH:28][CH:29]=[CH:30]2)[C:31](=[O:32])O.CN1CCOCC1.O.ON1N=NC2=C1C=CC=C2.Cl.C(C)N=C=NCCCN(C)C>CN(C=O)"
+ "C>[C:25]12=[CH:30][CH:29]=[CH:28][CH:27]=[C:26]1[CH:23]([C:31](=[O:32])[NH:1][C:2]1=[CH:3][CH:4]="
+ "[C:5]([C:8]3=[CH:9][N:10]=[C:11]([C:13]4([CH2:14][CH2:15][CH2:16]4)[O:17][CH2:18][C:19](=[O:20])"
+ "[OH:21])[S:12]3)[CH:6]=[CH:7]1)[CH2:24]2 |f:3.4,5.6|"),

Arguments.of("C1C=CC=C2CCC=12>>C1CCC1",
"[NH2:1][C:2]1=[CH:3][CH:4]=[C:5]([C:8]2=[CH:9][N:10]=[C:11]([C:13]3([CH2:14][CH2:15][CH2:16]3)[O:17]"
+ "[CH2:18][C:19](=[O:20])[O:21]C)[S:12]2)[CH:6]=[CH:7]1.[CH:23]1([CH2:24][C:25]2=[C:26]1[CH:27]="
+ "[CH:28][CH:29]=[CH:30]2)[C:31](=[O:32])O.CN1CCOCC1.O.ON1N=NC2=C1C=CC=C2.Cl.C(C)N=C=NCCCN(C)C>CN(C=O)"
+ "C>[C:25]12=[CH:30][CH:29]=[CH:28][CH:27]=[C:26]1[CH:23]([C:31](=[O:32])[NH:1][C:2]1=[CH:3][CH:4]="
+ "[C:5]([C:8]3=[CH:9][N:10]=[C:11]([C:13]4([CH2:14][CH2:15][CH2:16]4)[O:17][CH2:18][C:19](=[O:20])"
+ "[OH:21])[S:12]3)[CH:6]=[CH:7]1)[CH2:24]2 |f:3.4,5.6|\n"),

Arguments.of("C1C=CC=[C:3]2[CH2:8][CH2:7][C:2]=12>>[CH2:2]1[CH2:7][CH2:8][CH2:3]1",
"[NH2:1][C:2]1=[CH:3][CH:4]=[C:5]([C:8]2=[CH:9][N:10]=[C:11]([C:13]3([CH2:14][CH2:15][CH2:16]3)[O:17]"
+ "[CH2:18][C:19](=[O:20])[O:21]C)[S:12]2)[CH:6]=[CH:7]1.[CH:23]1([CH2:24][C:25]2=[C:26]1[CH:27]="
+ "[CH:28][CH:29]=[CH:30]2)[C:31](=[O:32])O.CN1CCOCC1.O.ON1N=NC2=C1C=CC=C2.Cl.C(C)N=C=NCCCN(C)C>CN(C=O)"
+ "C>[C:25]12=[CH:30][CH:29]=[CH:28][CH:27]=[C:26]1[CH:23]([C:31](=[O:32])[NH:1][C:2]1=[CH:3][CH:4]="
+ "[C:5]([C:8]3=[CH:9][N:10]=[C:11]([C:13]4([CH2:14][CH2:15][CH2:16]4)[O:17][CH2:18][C:19](=[O:20])"
+ "[OH:21])[S:12]3)[CH:6]=[CH:7]1)[CH2:24]2 |f:3.4,5.6|\n"),

Arguments.of("C1C=CC=[C:3]2[CH2:8][CH2:7][C:2]=12>>[CH2:2]1[CH2:7][CH2:8][CH2:3]1",
"[NH2:1][C:2]1=[CH:3][CH:4]=[C:5]([C:8]2=[CH:9][N:10]=[C:11]([C:13]3([CH2:14][CH2:15][CH2:16]3)[O:17]"
+ "[CH2:18][C:19](=[O:20])[O:21]C)[S:12]2)[CH:6]=[CH:7]1.[CH:23]1([CH2:24][C:25]2=[C:26]1[CH:27]="
+ "[CH:28][CH:29]=[CH:30]2)[C:31](=[O:32])O.CN1CCOCC1.O.ON1N=NC2=C1C=CC=C2.Cl.C(C)N=C=NCCCN(C)C>CN(C=O)"
+ "C>[C:25]12=[CH:30][CH:29]=[CH:28][CH:27]=[C:26]1[CH:23]([C:31](=[O:32])[NH:1][C:2]1=[CH:3][CH:4]="
+ "[C:5]([C:8]3=[CH:9][N:10]=[C:11]([C:13]4([CH2:14][CH2:15][CH2:16]4)[O:17][CH2:18][C:19](=[O:20])"
+ "[OH:21])[S:12]3)[CH:6]=[CH:7]1)[CH2:24]2 |f:3.4,5.6|")
);
}

@ParameterizedTest
@MethodSource("molecules")
void test(String source, String target) {
var substructureParams = SubstructureParams.builder().searchQuery(source).heteroatoms(false).build();
Assertions.assertTrue(new IndigoMatcher(new IndigoProvider(100, 5)).isReactionSubstructureMatch(target, substructureParams));
}
}
Loading