Skip to content

Commit

Permalink
refactor: some low hanging drive-by improvements that didn't make it …
Browse files Browse the repository at this point in the history
…into #842

resolves #991
  • Loading branch information
fengelniederhammer committed Feb 12, 2024
1 parent a7abbce commit 87591b1
Show file tree
Hide file tree
Showing 5 changed files with 79 additions and 89 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import kotlinx.datetime.toLocalDateTime
import mu.KotlinLogging
import org.jetbrains.exposed.sql.Database
import org.jetbrains.exposed.sql.SqlExpressionBuilder.eq
import org.jetbrains.exposed.sql.SqlExpressionBuilder.plus
import org.jetbrains.exposed.sql.and
import org.jetbrains.exposed.sql.andWhere
import org.jetbrains.exposed.sql.deleteWhere
Expand Down Expand Up @@ -180,10 +179,12 @@ class DatasetCitationsDatabaseService(

var selectedVersion = version

val datasetUuid = UUID.fromString(datasetId)

if (selectedVersion == null) {
selectedVersion = DatasetsTable
.slice(DatasetsTable.datasetVersion.max())
.select { DatasetsTable.datasetId eq UUID.fromString(datasetId) }
.select { DatasetsTable.datasetId eq datasetUuid }
.singleOrNull()?.get(DatasetsTable.datasetVersion)
}
if (selectedVersion == null) {
Expand All @@ -192,7 +193,7 @@ class DatasetCitationsDatabaseService(

if (DatasetToRecordsTable
.select {
(DatasetToRecordsTable.datasetId eq UUID.fromString(datasetId)) and
(DatasetToRecordsTable.datasetId eq datasetUuid) and
(DatasetToRecordsTable.datasetVersion eq selectedVersion)
}
.empty()
Expand All @@ -203,7 +204,7 @@ class DatasetCitationsDatabaseService(
val selectedDatasetRecords = DatasetToRecordsTable
.innerJoin(DatasetRecordsTable)
.select {
(DatasetToRecordsTable.datasetId eq UUID.fromString(datasetId)) and
(DatasetToRecordsTable.datasetId eq datasetUuid) and
(DatasetToRecordsTable.datasetVersion eq selectedVersion)
}
.map {
Expand Down Expand Up @@ -262,11 +263,13 @@ class DatasetCitationsDatabaseService(
throw NotFoundException("Dataset $datasetId, version $version does not exist")
}

DatasetsTable.update({
(DatasetsTable.datasetId eq UUID.fromString(datasetId)) and
(DatasetsTable.datasetVersion eq version) and
(DatasetsTable.createdBy eq username)
}) {
DatasetsTable.update(
{
(DatasetsTable.datasetId eq UUID.fromString(datasetId)) and
(DatasetsTable.datasetVersion eq version) and
(DatasetsTable.createdBy eq username)
},
) {
it[DatasetsTable.datasetDOI] = datasetDOI
}

Expand All @@ -284,6 +287,7 @@ class DatasetCitationsDatabaseService(
val datasetVersion: Long,
val createdAt: Timestamp,
)

val selectedDatasetRecords = DatasetRecordsTable
.innerJoin(DatasetToRecordsTable)
.innerJoin(DatasetsTable)
Expand Down Expand Up @@ -326,8 +330,8 @@ class DatasetCitationsDatabaseService(
.toSet()

val citedBy = CitedBy(
mutableListOf<Long>(),
mutableListOf<Long>(),
mutableListOf(),
mutableListOf(),
)
for (dataset in uniqueLatestDatasets) {
val year = dataset.createdAt.toLocalDateTime().year.toLong()
Expand Down Expand Up @@ -365,10 +369,7 @@ class DatasetCitationsDatabaseService(
where = { AuthorsTable.username eq username },
)
.firstOrNull()

if (selectedAuthor == null) {
throw NotFoundException("Author $username does not exist")
}
?: throw NotFoundException("Author $username does not exist")

return Author(
selectedAuthor[AuthorsTable.authorId],
Expand Down
68 changes: 26 additions & 42 deletions website/src/pages/datasets/index.astro
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import { ErrorFeedback } from '../../components/ErrorFeedback';
import { getRuntimeConfig } from '../../config';
import BaseLayout from '../../layouts/BaseLayout.astro';
import { DatasetCitationClient } from '../../services/datasetCitationClient.ts';
import { createAuthorizationHeader } from '../../utils/createAuthorizationHeader.ts';
import { getAccessToken } from '../../utils/getAccessToken';
const clientConfig = getRuntimeConfig().public;
Expand All @@ -17,30 +16,9 @@ const session = Astro.locals.session;
const datasetClient = DatasetCitationClient.create();
const datasetsResponse = (await datasetClient.call('getDatasetsOfUser', {
headers: createAuthorizationHeader(accessToken),
})) as any;
const userCitedByResponse = (await datasetClient.call('getUserCitedBy', {
params: { username },
headers: createAuthorizationHeader(accessToken),
})) as any;
const authorResponse = (await datasetClient.call('getAuthor', {
headers: createAuthorizationHeader(accessToken),
})) as any;
const handlePrivateAuthorProfile = (authorResponse: any, userSession: any) => {
const authorData = authorResponse ?? {};
return {
name: userSession?.name,
email: userSession?.email,
emailVerified: userSession?.email_verified,
...authorData,
};
};
const authorData = handlePrivateAuthorProfile(authorResponse.value, session.user);
const datasetsResponse = await datasetClient.getDatasetsOfUser(accessToken);
const userCitedByResponse = await datasetClient.getUserCitedBy(username, accessToken);
const authorResponse = await datasetClient.getAuthor(accessToken);
---

<BaseLayout title='Datasets' data-testid='datasets-list-container'>
Expand All @@ -53,7 +31,13 @@ const authorData = handlePrivateAuthorProfile(authorResponse.value, session.user
accessToken={accessToken}
fontSize={120}
client:load
{...authorData}
name={session.user?.name}
email={session.user?.email}
emailVerified={session.user?.emailVerified}
{...authorResponse.match<{ authorId: string | undefined; affiliation?: string | undefined }>(
(ok) => ok,
() => ({ authorId: undefined, affiliation: undefined }),
)}
/>
<hr />
<div class='flex justify-start'>
Expand All @@ -64,15 +48,14 @@ const authorData = handlePrivateAuthorProfile(authorResponse.value, session.user
</div>
<div>
{
datasetsResponse.value !== undefined ? (
<DatasetList datasets={datasetsResponse.value} username={username} client:load />
) : (
<ErrorFeedback
message={
'Error while fetching datasets: ' + JSON.stringify(datasetsResponse.error)
}
client:load
/>
datasetsResponse.match(
(datasets) => <DatasetList datasets={datasets} username={username} client:load />,
(error) => (
<ErrorFeedback
message={'Error while fetching datasets: ' + JSON.stringify(error)}
client:load
/>
),
)
}
</div>
Expand All @@ -82,13 +65,14 @@ const authorData = handlePrivateAuthorProfile(authorResponse.value, session.user
<div class='w-1/4 flex flex-col justify-start items-start pl-4'>
<span class='text-xl'>Cited By</span>
{
userCitedByResponse.value !== undefined ? (
<CitationPlot citedByData={userCitedByResponse.value} client:load />
) : (
<ErrorFeedback
message={'Error while fetching datasets: ' + JSON.stringify(userCitedByResponse.error)}
client:load
/>
userCitedByResponse.match(
(citedByData) => <CitationPlot citedByData={citedByData} client:load />,
(error) => (
<ErrorFeedback
message={'Error while fetching datasets: ' + JSON.stringify(error)}
client:load
/>
),
)
}
</div>
Expand Down
5 changes: 1 addition & 4 deletions website/src/routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,7 @@ export const routes = {
const userPagePath = `/user` as const;
return organism === undefined ? userPagePath : withOrganism(organism, userPagePath);
},
groupOverviewPage: (groupName: string) => {
const groupPagePath = `/group/${groupName}` as const;
return groupPagePath;
},
groupOverviewPage: (groupName: string) => `/group/${groupName}`,
userSequencesPage: (organism: string) => withOrganism(organism, `/user/seq`),
userSequenceReviewPage: (organism: string) => withOrganism(organism, `/submit/review`),
versionPage: (organism: string, accession: string) => withOrganism(organism, `/seq/${accession}/versions`),
Expand Down
20 changes: 20 additions & 0 deletions website/src/services/datasetCitationClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { datasetCitationApi } from './datasetCitationApi.ts';
import { ZodiosWrapperClient } from './zodiosWrapperClient.ts';
import { getRuntimeConfig } from '../config.ts';
import { getInstanceLogger } from '../logger.ts';
import { createAuthorizationHeader } from '../utils/createAuthorizationHeader.ts';

export class DatasetCitationClient extends ZodiosWrapperClient<typeof datasetCitationApi> {
public static create(
Expand All @@ -16,4 +17,23 @@ export class DatasetCitationClient extends ZodiosWrapperClient<typeof datasetCit
'backend',
);
}

public getDatasetsOfUser(accessToken: string) {
return this.call('getDatasetsOfUser', {
headers: createAuthorizationHeader(accessToken),
});
}

public getUserCitedBy(username: string, accessToken: string) {
return this.call('getUserCitedBy', {
params: { username },
headers: createAuthorizationHeader(accessToken),
});
}

public getAuthor(accessToken: string) {
return this.call('getAuthor', {
headers: createAuthorizationHeader(accessToken),
});
}
}
44 changes: 16 additions & 28 deletions website/src/utils/parseAccessionInput.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,53 +21,41 @@ export const serializeRecordsToAccessionsInput = (records?: DatasetRecord[], del
};
};

const nucleotidePatterns = [/^[A-Z]{1}\d{5}$/, /^[A-Z]{2}\d{6}$/, /^[A-Z]{2}\d{8}$/];
const proteinPatterns = [/^[A-Z]{3}\d{5}$/, /^[A-Z]{3}\d{7}$/];
const wgsPatterns = [/^[A-Z]{4}\d{2}\d{6,}$/, /^[A-Z]{6}\d{2}\d{7,}$/];
const mgaPatterns = [/^[A-Z]{5}\d{7}$/];

const validateGenbankAccession = (accession: string): boolean => {
// https://www.ncbi.nlm.nih.gov/genbank/acc_prefix/

// Nucleotide patterns
const nucleotidePatterns = [/^[A-Z]{1}\d{5}$/, /^[A-Z]{2}\d{6}$/, /^[A-Z]{2}\d{8}$/];

// Protein patterns
const proteinPatterns = [/^[A-Z]{3}\d{5}$/, /^[A-Z]{3}\d{7}$/];

// WGS patterns
const wgsPatterns = [/^[A-Z]{4}\d{2}\d{6,}$/, /^[A-Z]{6}\d{2}\d{7,}$/];

// MGA pattern
const mgaPatterns = [/^[A-Z]{5}\d{7}$/];

return [...nucleotidePatterns, ...proteinPatterns, ...wgsPatterns, ...mgaPatterns].some((pattern) =>
pattern.test(accession),
);
};

const validateSRAAccession = (accession: string): boolean => {
// Study patterns
const studyPatterns = [/^SRP\d+$/, /^ERP\d+$/, /^DRP\d+$/];

// Sample patterns
const samplePatterns = [/^SRS\d+$/, /^ERS\d+$/, /^DRS\d+$/];

// Experiment patterns
const experimentPatterns = [/^SRX\d+$/, /^ERX\d+$/, /^DRX\d+$/];

// Run patterns
const runPatterns = [/^SRR\d+$/, /^ERR\d+$/, /^DRR\d+$/];
const studyPatterns = [/^SRP\d+$/, /^ERP\d+$/, /^DRP\d+$/];
const samplePatterns = [/^SRS\d+$/, /^ERS\d+$/, /^DRS\d+$/];
const experimentPatterns = [/^SRX\d+$/, /^ERX\d+$/, /^DRX\d+$/];
const runPatterns = [/^SRR\d+$/, /^ERR\d+$/, /^DRR\d+$/];

const validateSRAAccession = (accession: string): boolean => {
return [...studyPatterns, ...samplePatterns, ...experimentPatterns, ...runPatterns].some((pattern) =>
pattern.test(accession),
);
};

const gisaidPatterns = [/^EPI_ISL_\d+$/];

const validateGISAIDAccession = (accession: string): boolean => {
const gisaidPatterns = [/^EPI_ISL_\d+$/];
return gisaidPatterns.some((pattern) => pattern.test(accession));
};

// TODO: update after finalizing accession format:
// https://github.com/loculus-project/loculus/issues/444
const loculusPatterns = [/^[A-Z]+_\d+(\.\d+)?(\d+)?$/];

const validateLoculusAccession = (accession: string): boolean => {
// TODO: update after finalizing accession format:
// https://github.com/loculus-project/loculus/issues/444
const loculusPatterns = [/^[A-Z]+_\d+(\.\d+)?(\d+)?$/];
return loculusPatterns.some((pattern) => pattern.test(accession));
};

Expand Down

0 comments on commit 87591b1

Please sign in to comment.