-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add ability to define custom aliases for refSeq names (#419)
* refname alias UI * refname alias UI * refname alias UI * refname alias UI * cleanup * refname alias cli * update alias on client session * update alias on client session * refname alias editable row * Standardize AddRefSeqAliasesChange --------- Co-authored-by: Garrett Stevens <stevens.garrett.j@gmail.com>
- Loading branch information
1 parent
3c101e1
commit 59969bf
Showing
13 changed files
with
565 additions
and
12 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,102 @@ | ||
import * as fs from 'node:fs' | ||
import { Agent, RequestInit, Response, fetch } from 'undici' | ||
import { Flags } from '@oclif/core' | ||
import { BaseCommand } from '../../baseCommand.js' | ||
import { | ||
createFetchErrorMessage, | ||
localhostToAddress, | ||
queryApollo, | ||
wrapLines, | ||
} from '../../utils.js' | ||
import { ConfigError } from '../../ApolloConf.js' | ||
|
||
export default class AddRefNameAlias extends BaseCommand< | ||
typeof AddRefNameAlias | ||
> { | ||
static summary = 'Add reference name aliases from a file' | ||
static description = wrapLines( | ||
'Reference name aliasing is a process to make chromosomes that are named slightly differently but which refer to the same thing render properly. This command reads a file with reference name aliases and adds them to the database.', | ||
) | ||
|
||
static examples = [ | ||
{ | ||
description: 'Add reference name aliases:', | ||
command: '<%= config.bin %> <%= command.id %> -i alias.txt -a myAssembly', | ||
}, | ||
] | ||
|
||
static flags = { | ||
'input-file': Flags.string({ | ||
char: 'i', | ||
description: 'Input refname alias file', | ||
required: true, | ||
}), | ||
assembly: Flags.string({ | ||
char: 'a', | ||
description: 'Name for this assembly.', | ||
required: true, | ||
}), | ||
} | ||
|
||
async run(): Promise<void> { | ||
const { flags } = await this.parse(AddRefNameAlias) | ||
|
||
if (!fs.existsSync(flags['input-file'])) { | ||
this.error(`File ${flags['input-file']} does not exist`) | ||
} | ||
|
||
const access: { address: string; accessToken: string } = | ||
await this.getAccess(flags['config-file'], flags.profile) | ||
const filehandle = await fs.promises.open(flags['input-file']) | ||
const fileContent = await filehandle.readFile({ encoding: 'utf8' }) | ||
await filehandle.close() | ||
const lines = fileContent.split('\n') | ||
|
||
const refNameAliases = [] | ||
for (const line of lines) { | ||
const [refName, ...aliases] = line.split('\t') | ||
refNameAliases.push({ refName, aliases }) | ||
} | ||
|
||
const assemblies: Response = await queryApollo( | ||
access.address, | ||
access.accessToken, | ||
'assemblies', | ||
) | ||
const json = (await assemblies.json()) as object[] | ||
const assembly = json.find((x) => 'name' in x && x.name === flags.assembly) | ||
const assemblyId = assembly && '_id' in assembly ? assembly._id : undefined | ||
|
||
if (!assemblyId) { | ||
this.error(`Assembly ${flags.assembly} not found`) | ||
} | ||
|
||
const change = { | ||
typeName: 'AddRefSeqAliasesChange', | ||
assembly: assemblyId, | ||
refSeqAliases: refNameAliases, | ||
} | ||
|
||
const auth: RequestInit = { | ||
method: 'POST', | ||
body: JSON.stringify(change), | ||
headers: { | ||
Authorization: `Bearer ${access.accessToken}`, | ||
'Content-Type': 'application/json', | ||
}, | ||
dispatcher: new Agent({ headersTimeout: 60 * 60 * 1000 }), | ||
} | ||
const url = new URL(localhostToAddress(`${access.address}/changes`)) | ||
const response = await fetch(url, auth) | ||
if (!response.ok) { | ||
const errorMessage = await createFetchErrorMessage( | ||
response, | ||
'Failed to add reference name aliases', | ||
) | ||
throw new ConfigError(errorMessage) | ||
} | ||
this.log( | ||
`Reference name aliases added successfully to assembly ${flags.assembly}`, | ||
) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
ctgA ctga CTGA | ||
ctgB ctgb CTGB | ||
ctgC ctgc CTGC |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
88 changes: 88 additions & 0 deletions
88
packages/apollo-shared/src/Changes/AddRefSeqAliasesChange.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,88 @@ | ||
import { | ||
AssemblySpecificChange, | ||
Change, | ||
ChangeOptions, | ||
ClientDataStore, | ||
LocalGFF3DataStore, | ||
SerializedAssemblySpecificChange, | ||
ServerDataStore, | ||
} from '@apollo-annotation/common' | ||
import { getSession } from '@jbrowse/core/util' | ||
|
||
export interface SerializedRefSeqAliases { | ||
refName: string | ||
aliases: string[] | ||
} | ||
|
||
export interface SerializedRefSeqAliasesChange | ||
extends SerializedAssemblySpecificChange { | ||
typeName: 'AddRefSeqAliasesChange' | ||
refSeqAliases: SerializedRefSeqAliases[] | ||
} | ||
|
||
export class AddRefSeqAliasesChange extends AssemblySpecificChange { | ||
typeName = 'AddRefSeqAliasesChange' as const | ||
refSeqAliases: SerializedRefSeqAliases[] | ||
|
||
constructor(json: SerializedRefSeqAliasesChange, options?: ChangeOptions) { | ||
super(json, options) | ||
this.refSeqAliases = json.refSeqAliases | ||
} | ||
|
||
executeOnClient(clientDataStore: ClientDataStore) { | ||
const { assemblyManager } = getSession(clientDataStore) | ||
const assembly = assemblyManager.get(this.assembly) | ||
if (!assembly) { | ||
throw new Error(`assembly ${this.assembly} not found`) | ||
} | ||
const sessionAliases = assembly.refNameAliases | ||
const sessionLCAliases = assembly.lowerCaseRefNameAliases | ||
|
||
if (!sessionAliases || !sessionLCAliases) { | ||
throw new Error('Session refNameAliases not found in assembly') | ||
} | ||
|
||
for (const refSeqAlias of this.refSeqAliases) { | ||
const { aliases, refName } = refSeqAlias | ||
for (const alias of aliases) { | ||
sessionAliases[alias] = refName | ||
sessionLCAliases[alias.toLowerCase()] = refName | ||
} | ||
} | ||
assembly.setRefNameAliases(sessionAliases, sessionLCAliases) | ||
return Promise.resolve() | ||
} | ||
|
||
getInverse(): Change { | ||
throw new Error('Method not implemented.') | ||
} | ||
|
||
toJSON(): SerializedRefSeqAliasesChange { | ||
const { assembly, refSeqAliases, typeName } = this | ||
return { assembly, typeName, refSeqAliases } | ||
} | ||
|
||
async executeOnServer(backend: ServerDataStore) { | ||
const { refSeqModel, session } = backend | ||
const { assembly, logger, refSeqAliases } = this | ||
|
||
for (const refSeqAlias of refSeqAliases) { | ||
logger.debug?.( | ||
`Updating Refname alias for assembly: ${assembly}, refSeqAlias: ${JSON.stringify(refSeqAlias)}`, | ||
) | ||
const { aliases, refName } = refSeqAlias | ||
await refSeqModel | ||
.updateOne({ assembly, name: refName }, { $set: { aliases } }) | ||
.session(session) | ||
} | ||
} | ||
|
||
executeOnLocalGFF3(_backend: LocalGFF3DataStore): Promise<unknown> { | ||
throw new Error('Method not implemented.') | ||
} | ||
|
||
// eslint-disable-next-line @typescript-eslint/class-literal-property-style | ||
get notification(): string { | ||
return 'RefSeq aliases have been added.' | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.