benchling_typescript_sdk
Version:
Typescript SDK for Benchling API
117 lines (115 loc) • 4.71 kB
text/typescript
import { connect } from "http2";
import { BenchlingClient } from "../BenchlingClient";
import { ContainerQuantity, MultipleContainersTransfer, Plate, SmallPlate } from "../types";
import { chunkArray } from "./chunkQueries";
/**
* Given Plate[] - empty contents and then recreate the plate according to Plate[]
* This is use to undo and restore previous versions of plates with potentially mixed contents in wells.
*/
export class ReCreatePlatesContents {
private benchling: BenchlingClient;
constructor(client: BenchlingClient) {
this.benchling = client;
}
public async reCreatePlatesContents(originalPlates: SmallPlate[]): Promise<boolean> {
try {
// First, we need to empty the contents of the current plates
let generator = this.benchling.plates.listSmallPlates({
ids: originalPlates.map((p) => p.id).join(","),
});
for await (const currentPlates of generator) {
currentPlates.forEach(async (plate) => {
Object.keys(plate.wells).forEach(async (wellId) => {
plate.wells[wellId].contents?.forEach(async (content) => {
// delete whatever content is there currently. can only do one at a time :/
await this.benchling.containers.deleteContainerContent(
// does this error if it doesn't work? must test
plate.wells[wellId].id,
content.entity.id
);
});
});
});
}
} catch (error: unknown) {
console.error("\nUnable to DELETE container contents to recreate plates\n");
throw error;
}
// now all content is deleted
// lets re-create the originalPlates by creating transfers
let transfers: MultipleContainersTransfer[] = [];
try {
for (const plate of originalPlates) {
for (const wellId in plate.wells) {
let well = plate.wells[wellId];
if (!well.quantity || !well.quantity.value || !well.quantity.units) {
continue;
}
if (well.quantity.units !== "mL" && well.quantity.units !== "uL") {
throw Error(
`Unsupported volume quantity unit in plate ${plate.barcode}:${wellId} - ${well.quantity.units} - must be 'uL' or 'mL'`
);
}
let quantityValue: number = well.quantity.value;
let quanityUnits = well.quantity.units as "mL" | "uL";
let transferVolume: number = Math.floor(quantityValue || 0 / well.contents.length);
let additionalVolume = quantityValue - transferVolume * well.contents.length;
well.contents.forEach((content, i) => {
let destinationContainerId: string = well.id;
let sourceEntityId = content.entity.id;
transfers.push({
destinationContainerId,
sourceEntityId,
transferQuantity: {
units: quanityUnits,
value: i === 0 ? transferVolume + additionalVolume : transferVolume,
},
});
}); // add correct whole volume here - will use the other endpoint to update concentrations
}
}
} catch (error: unknown) {
console.error(
"\nUnable to transfer entity volumes back into emptied plates in ReCreatePlatesContents\n"
); // Safely access the error message)
throw error;
}
// now run the transferes
try {
await this.benchling.containers.waitForAllTransfers(transfers, 1000);
} catch (error: unknown) {
console.error("Error during entity volume transfers");
throw error;
}
try {
for (const plate of originalPlates) {
for (const wellId in plate.wells) {
let well = plate.wells[wellId];
if (!well.quantity || !well.quantity.value || !well.quantity.units) {
continue;
}
well.contents.forEach(async (content) => {
if (
content.entity.id &&
content.concentration &&
content.concentration.value !== null &&
content.concentration.units !== null
) {
// we need to update the concentration of the entity in the well
await this.benchling.containers.patchContainerContent(
well.id,
content.entity.id,
content.concentration
);
}
});
}
}
} catch (error: unknown) {
console.error("Error updating concentrations during ReCreatePlatesContents");
throw error;
// now the plates have the correct entities at a volume, but do not have concentrations
}
return true; // this should have worked!!
}
}