mirror of
https://github.com/chanzuckerberg/cellxgene.git
synced 2026-10-01 07:58:12 +08:00
TS Revert (1) (#2402)
* revert all commits to before Typescript migration * update compat workflow to match latest deps (#2335) * update compat workflow to match latest deps * attempt to debug * attempt to debug * remove debugging code * typo * update deps to match desktop (#2340) * fix: don't run lint with `--fix` on push tests (#2273) * fix: don't run lint with `--fix` on push tests * npx Co-authored-by: maniarathi <mani.arathi@gmail.com> Co-authored-by: Madison Dunitz <madison.dunitz@chanzuckerberg.com> * rename X_approx_distribution to X_approximate_distribution (#2337) * Correctly handle non-finite numbers in heuristic determination of X distribution (#2342) * handle non-finites explicitly * improve and test edge case handling for distribution estimation * revert debugging changes * code readability * clean up type inferencing (#2332) * unit tests for 64 bit conversion * clean up type handling * type inference tests * more type inference fixes * use schema to determine user intent for data typing * stop using deprecated API * fbs type encoding test * add missing test * add more tests * correctly infer X type for CXG adaptor * lint * fix typo * ts migration * cleanup from PR review * lint * PR review changes * remove unused packages from client (#2359) * remove unused packages from client * add missing peer dep * fix: disable FE auth testing on compatibility tests (#2377) * update: release process (#2277) Co-authored-by: maniarathi <mani.arathi@gmail.com> * fix: remove spaces in param setup (#2380) * delete deploy workflow (#2396) * undo reformatting which now does not pass lint * fix snapshots which changed due to npm dep changes * add missing quoting to snapshot * another snapshot typo fix * TS Revert (2) - replay PR #2347 and #2354 (#2403) * replay edits from PR 2347 * TS Revert (3) - replay edits in PR #2327 (#2404) * replay edits in PR 2327 * TS Revert (4) - replay PR #2355 (#2405) * replay edits in PR 2355 * add additional babel config * reformat with new prettier config Co-authored-by: Severiano Badajoz <sbadajoz@chanzuckerberg.com> Co-authored-by: maniarathi <mani.arathi@gmail.com> Co-authored-by: Madison Dunitz <madison.dunitz@chanzuckerberg.com>
This commit is contained in:
co-authored by
maniarathi
Madison Dunitz
Severiano Badajoz
parent
295590a7c6
commit
eaae6df5e3
+54
-79
@@ -10,18 +10,14 @@ import {
|
||||
isubsetMask,
|
||||
} from "../../../src/annoMatrix";
|
||||
import { Dataframe } from "../../../src/util/dataframe";
|
||||
import { Field } from "../../../src/common/types/schema";
|
||||
|
||||
enableFetchMocks();
|
||||
|
||||
describe("AnnoMatrix", () => {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS.
|
||||
let annoMatrix: any;
|
||||
let annoMatrix;
|
||||
|
||||
beforeEach(async () => {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS.
|
||||
(fetch as any).resetMocks(); // reset all fetch mocking state
|
||||
// reset all fetch mocking state
|
||||
fetch.resetMocks(); // reset all fetch mocking state
|
||||
annoMatrix = new AnnoMatrixLoader(
|
||||
serverMocks.baseDataURL,
|
||||
serverMocks.schema.schema
|
||||
@@ -35,67 +31,58 @@ describe("AnnoMatrix", () => {
|
||||
expect(annoMatrix.nObs).toEqual(serverMocks.schema.schema.dataframe.nObs);
|
||||
expect(annoMatrix.nVar).toEqual(serverMocks.schema.schema.dataframe.nVar);
|
||||
expect(annoMatrix.isView).toBeFalsy();
|
||||
expect(annoMatrix.viewOf).toBe(annoMatrix);
|
||||
expect(annoMatrix.viewOf).toBeUndefined();
|
||||
expect(annoMatrix.rowIndex).toBeDefined();
|
||||
});
|
||||
|
||||
test("simple single column fetch", async () => {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS.
|
||||
(fetch as any).once(serverMocks.annotationsObs(["name_0"]));
|
||||
fetch.once(serverMocks.annotationsObs(["name_0"]));
|
||||
|
||||
const df = await annoMatrix.fetch(Field.obs, "name_0");
|
||||
const df = await annoMatrix.fetch("obs", "name_0");
|
||||
expect(df).toBeInstanceOf(Dataframe);
|
||||
expect(df.colIndex.labels()).toEqual(["name_0"]);
|
||||
expect(df.dims).toEqual([annoMatrix.nObs, 1]);
|
||||
});
|
||||
|
||||
test("simple multi column fetch", async () => {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS.
|
||||
(fetch as any)
|
||||
fetch
|
||||
.once(serverMocks.annotationsObs(["name_0"]))
|
||||
.once(serverMocks.annotationsObs(["n_genes"]));
|
||||
|
||||
await expect(
|
||||
annoMatrix.fetch(Field.obs, ["name_0", "n_genes"])
|
||||
annoMatrix.fetch("obs", ["name_0", "n_genes"])
|
||||
).resolves.toBeInstanceOf(Dataframe);
|
||||
});
|
||||
|
||||
describe("fetch from field", () => {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS.
|
||||
const getLastTwo = async (field: any) => {
|
||||
const getLastTwo = async (field) => {
|
||||
const columnNames = annoMatrix.getMatrixColumns(field).slice(-2);
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS.
|
||||
(fetch as any).mockResponses(
|
||||
...columnNames.map(() => serverMocks.responder)
|
||||
);
|
||||
fetch.mockResponses(...columnNames.map(() => serverMocks.responder));
|
||||
await expect(
|
||||
annoMatrix.fetch(field, columnNames)
|
||||
).resolves.toBeInstanceOf(Dataframe);
|
||||
};
|
||||
|
||||
test(Field.obs, async () => getLastTwo(Field.obs));
|
||||
test("obs", async () => getLastTwo("obs"));
|
||||
test("var", async () => getLastTwo("var"));
|
||||
test("emb", async () => getLastTwo("emb"));
|
||||
});
|
||||
|
||||
test("fetch - test all query forms", async () => {
|
||||
// single string is a column name
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS.
|
||||
(fetch as any).once(serverMocks.annotationsObs(["n_genes"]));
|
||||
await expect(
|
||||
annoMatrix.fetch(Field.obs, "n_genes")
|
||||
).resolves.toBeInstanceOf(Dataframe);
|
||||
fetch.once(serverMocks.annotationsObs(["n_genes"]));
|
||||
await expect(annoMatrix.fetch("obs", "n_genes")).resolves.toBeInstanceOf(
|
||||
Dataframe
|
||||
);
|
||||
|
||||
// array of column names, expecting n_genes to be cached.
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS.
|
||||
(fetch as any).once(serverMocks.annotationsObs(["percent_mito"]));
|
||||
fetch.once(serverMocks.annotationsObs(["percent_mito"]));
|
||||
await expect(
|
||||
annoMatrix.fetch(Field.obs, ["n_genes", "percent_mito"])
|
||||
annoMatrix.fetch("obs", ["n_genes", "percent_mito"])
|
||||
).resolves.toBeInstanceOf(Dataframe);
|
||||
|
||||
// more complex value filter query, enumerated
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS.
|
||||
(fetch as any).once(serverMocks.responder);
|
||||
fetch.once(serverMocks.responder);
|
||||
await expect(
|
||||
annoMatrix.fetch("X", {
|
||||
where: {
|
||||
@@ -108,8 +95,7 @@ describe("AnnoMatrix", () => {
|
||||
|
||||
// more complex value filter query, range
|
||||
const varIndex = annoMatrix.schema.annotations.var.index;
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS.
|
||||
(fetch as any)
|
||||
fetch
|
||||
.once(
|
||||
serverMocks.withExpected("/data/var", [[`var:${varIndex}`, "SUMO3"]])
|
||||
)
|
||||
@@ -152,9 +138,9 @@ describe("AnnoMatrix", () => {
|
||||
|
||||
test("schema accessors", () => {
|
||||
expect(annoMatrix.getMatrixFields()).toEqual(
|
||||
expect.arrayContaining(["X", Field.obs, "emb", "var"])
|
||||
expect.arrayContaining(["X", "obs", "emb", "var"])
|
||||
);
|
||||
expect(annoMatrix.getMatrixColumns(Field.obs)).toEqual(
|
||||
expect(annoMatrix.getMatrixColumns("obs")).toEqual(
|
||||
expect.arrayContaining(["name_0", "n_genes", "louvain"])
|
||||
);
|
||||
expect(annoMatrix.getColumnSchema("emb", "umap")).toEqual({
|
||||
@@ -172,7 +158,7 @@ describe("AnnoMatrix", () => {
|
||||
test the mask & label access to subset via isubset and isubsetMask
|
||||
*/
|
||||
test("isubset", async () => {
|
||||
const rowList = new Int32Array([0, 10]);
|
||||
const rowList = [0, 10];
|
||||
const rowMask = new Uint8Array(annoMatrix.nObs);
|
||||
for (let i = 0; i < rowList.length; i += 1) {
|
||||
rowMask[rowList[i]] = 1;
|
||||
@@ -185,14 +171,11 @@ describe("AnnoMatrix", () => {
|
||||
expect(am1.nObs).toEqual(am2.nObs);
|
||||
expect(am1.nVar).toEqual(am2.nVar);
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS.
|
||||
(fetch as any)
|
||||
fetch
|
||||
.once(serverMocks.annotationsObs(["n_genes"]))
|
||||
.once(serverMocks.annotationsObs(["n_genes"]));
|
||||
const ng1 = (await am1.fetch(Field.obs, "n_genes")) as Dataframe;
|
||||
const ng2 = (await am2.fetch(Field.obs, "n_genes")) as Dataframe;
|
||||
expect(ng1).toBeDefined();
|
||||
expect(ng2).toBeDefined();
|
||||
const ng1 = await am1.fetch("obs", "n_genes");
|
||||
const ng2 = await am2.fetch("obs", "n_genes");
|
||||
expect(ng1).toHaveLength(ng2.length);
|
||||
expect(ng1.colIndex.labels()).toEqual(ng2.colIndex.labels());
|
||||
expect(ng1.col("n_genes").asArray()).toEqual(
|
||||
@@ -202,12 +185,10 @@ describe("AnnoMatrix", () => {
|
||||
});
|
||||
|
||||
describe("add/drop column", () => {
|
||||
// @ts-expect-error ts-migrate(7006) FIXME: Parameter 'base' implicitly has an 'any' type.
|
||||
async function addDrop(base) {
|
||||
expect(base.getMatrixColumns(Field.obs)).not.toContain("foo");
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS.
|
||||
(fetch as any).mockRejectOnce(new Error("unknown column name"));
|
||||
await expect(base.fetch(Field.obs, "foo")).rejects.toThrow(
|
||||
expect(base.getMatrixColumns("obs")).not.toContain("foo");
|
||||
fetch.mockRejectOnce(new Error("unknown column name"));
|
||||
await expect(base.fetch("obs", "foo")).rejects.toThrow(
|
||||
"unknown column name"
|
||||
);
|
||||
|
||||
@@ -217,9 +198,9 @@ describe("AnnoMatrix", () => {
|
||||
Float32Array,
|
||||
0
|
||||
);
|
||||
expect(base.getMatrixColumns(Field.obs)).not.toContain("foo");
|
||||
expect(am1.getMatrixColumns(Field.obs)).toContain("foo");
|
||||
const foo: Dataframe = await am1.fetch(Field.obs, "foo");
|
||||
expect(base.getMatrixColumns("obs")).not.toContain("foo");
|
||||
expect(am1.getMatrixColumns("obs")).toContain("foo");
|
||||
const foo = await am1.fetch("obs", "foo");
|
||||
expect(foo).toBeDefined();
|
||||
expect(foo).toBeInstanceOf(Dataframe);
|
||||
expect(foo).toHaveLength(am1.nObs);
|
||||
@@ -229,11 +210,10 @@ describe("AnnoMatrix", () => {
|
||||
|
||||
/* drop */
|
||||
const am2 = am1.dropObsColumn("foo");
|
||||
expect(base.getMatrixColumns(Field.obs)).not.toContain("foo");
|
||||
expect(am2.getMatrixColumns(Field.obs)).not.toContain("foo");
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS.
|
||||
(fetch as any).mockRejectOnce(new Error("unknown column name"));
|
||||
await expect(am2.fetch(Field.obs, "foo")).rejects.toThrow(
|
||||
expect(base.getMatrixColumns("obs")).not.toContain("foo");
|
||||
expect(am2.getMatrixColumns("obs")).not.toContain("foo");
|
||||
fetch.mockRejectOnce(new Error("unknown column name"));
|
||||
await expect(am2.fetch("obs", "foo")).rejects.toThrow(
|
||||
"unknown column name"
|
||||
);
|
||||
}
|
||||
@@ -246,25 +226,23 @@ describe("AnnoMatrix", () => {
|
||||
const am1 = clip(annoMatrix, 0.1, 0.9);
|
||||
await addDrop(am1);
|
||||
|
||||
const am2 = isubset(am1, new Int32Array([0, 1, 2, 20, 30, 400]));
|
||||
const am2 = isubset(am1, [0, 1, 2, 20, 30, 400]);
|
||||
await addDrop(am2);
|
||||
|
||||
const am3 = isubset(annoMatrix, new Int32Array([10, 0, 7, 3]));
|
||||
const am3 = isubset(annoMatrix, [10, 0, 7, 3]);
|
||||
await addDrop(am3);
|
||||
|
||||
const am4 = clip(am3, 0, 1);
|
||||
await addDrop(am4);
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS.
|
||||
(fetch as any).mockResponse(serverMocks.responder);
|
||||
fetch.mockResponse(serverMocks.responder);
|
||||
|
||||
await am1.fetch(Field.obs, am1.getMatrixColumns(Field.obs));
|
||||
await am2.fetch(Field.obs, am2.getMatrixColumns(Field.obs));
|
||||
await am3.fetch(Field.obs, am3.getMatrixColumns(Field.obs));
|
||||
await am4.fetch(Field.obs, am4.getMatrixColumns(Field.obs));
|
||||
await am1.fetch("obs", am1.getMatrixColumns("obs"));
|
||||
await am2.fetch("obs", am2.getMatrixColumns("obs"));
|
||||
await am3.fetch("obs", am3.getMatrixColumns("obs"));
|
||||
await am4.fetch("obs", am4.getMatrixColumns("obs"));
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS.
|
||||
(fetch as any).resetMocks();
|
||||
fetch.resetMocks();
|
||||
|
||||
await addDrop(am1);
|
||||
await addDrop(am2);
|
||||
@@ -274,7 +252,6 @@ describe("AnnoMatrix", () => {
|
||||
});
|
||||
|
||||
describe("setObsColumnValues", () => {
|
||||
// @ts-expect-error ts-migrate(7006) FIXME: Parameter 'base' implicitly has an 'any' type.
|
||||
async function addSetDrop(base) {
|
||||
/* add column */
|
||||
let am = base.addObsColumn(
|
||||
@@ -288,7 +265,7 @@ describe("AnnoMatrix", () => {
|
||||
"unassigned"
|
||||
);
|
||||
|
||||
const testVal = await am.fetch(Field.obs, "test");
|
||||
const testVal = await am.fetch("obs", "test");
|
||||
expect(testVal.col("test").asArray()).toEqual(
|
||||
new Array(am.nObs).fill("unassigned")
|
||||
);
|
||||
@@ -296,7 +273,7 @@ describe("AnnoMatrix", () => {
|
||||
/* set values in column */
|
||||
const whichRows = [1, 2, 10];
|
||||
const am1 = await am.setObsColumnValues("test", whichRows, "yo");
|
||||
const testVal1 = await am1.fetch(Field.obs, "test");
|
||||
const testVal1 = await am1.fetch("obs", "test");
|
||||
const expt = new Array(am1.nObs).fill("unassigned");
|
||||
for (let i = 0; i < whichRows.length; i += 1) {
|
||||
const offset = am1.rowIndex.getOffset(whichRows[i]);
|
||||
@@ -304,16 +281,15 @@ describe("AnnoMatrix", () => {
|
||||
}
|
||||
expect(testVal1).not.toBe(testVal);
|
||||
expect(testVal1.col("test").asArray()).toEqual(expt);
|
||||
expect(am1.getColumnSchema(Field.obs, "test").type).toBe("categorical");
|
||||
expect(am1.getColumnSchema(Field.obs, "test").categories).toEqual(
|
||||
expect(am1.getColumnSchema("obs", "test").type).toBe("categorical");
|
||||
expect(am1.getColumnSchema("obs", "test").categories).toEqual(
|
||||
expect.arrayContaining(["unassigned", "red", "green", "yo"])
|
||||
);
|
||||
|
||||
/* drop column */
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS.
|
||||
(fetch as any).mockRejectOnce(new Error("unknown column name"));
|
||||
fetch.mockRejectOnce(new Error("unknown column name"));
|
||||
am = am1.dropObsColumn("test");
|
||||
await expect(am.fetch(Field.obs, "test")).rejects.toThrow(
|
||||
await expect(am.fetch("obs", "test")).rejects.toThrow(
|
||||
"unknown column name"
|
||||
);
|
||||
}
|
||||
@@ -326,18 +302,17 @@ describe("AnnoMatrix", () => {
|
||||
const am1 = clip(annoMatrix, 0.1, 0.9);
|
||||
await addSetDrop(am1);
|
||||
|
||||
const am2 = isubset(am1, new Int32Array([0, 1, 2, 10, 20, 30, 400]));
|
||||
const am2 = isubset(am1, [0, 1, 2, 10, 20, 30, 400]);
|
||||
await addSetDrop(am2);
|
||||
|
||||
const am3 = isubset(annoMatrix, new Int32Array([10, 1, 0, 30, 2]));
|
||||
const am3 = isubset(annoMatrix, [10, 1, 0, 30, 2]);
|
||||
await addSetDrop(am3);
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS.
|
||||
(fetch as any).mockResponse(serverMocks.responder);
|
||||
fetch.mockResponse(serverMocks.responder);
|
||||
|
||||
await am1.fetch(Field.obs, am1.getMatrixColumns(Field.obs));
|
||||
await am2.fetch(Field.obs, am2.getMatrixColumns(Field.obs));
|
||||
await am3.fetch(Field.obs, am3.getMatrixColumns(Field.obs));
|
||||
await am1.fetch("obs", am1.getMatrixColumns("obs"));
|
||||
await am2.fetch("obs", am2.getMatrixColumns("obs"));
|
||||
await am3.fetch("obs", am3.getMatrixColumns("obs"));
|
||||
|
||||
await addSetDrop(am1);
|
||||
await addSetDrop(am2);
|
||||
+129
-196
@@ -12,25 +12,19 @@ import {
|
||||
AnnoMatrixObsCrossfilter,
|
||||
isubsetMask,
|
||||
} from "../../../src/annoMatrix";
|
||||
import { Dataframe } from "../../../src/util/dataframe";
|
||||
import { rangeFill } from "../../../src/util/range";
|
||||
import { Field, Schema } from "../../../src/common/types/schema";
|
||||
|
||||
enableFetchMocks();
|
||||
|
||||
describe("AnnoMatrixCrossfilter", () => {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS.
|
||||
let annoMatrix: any;
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS.
|
||||
let crossfilter: any;
|
||||
let annoMatrix;
|
||||
let crossfilter;
|
||||
|
||||
beforeEach(async () => {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS.
|
||||
(fetch as any).resetMocks(); // reset all fetch mocking state
|
||||
// reset all fetch mocking state
|
||||
fetch.resetMocks(); // reset all fetch mocking state
|
||||
annoMatrix = new AnnoMatrixLoader(
|
||||
serverMocks.baseDataURL,
|
||||
serverMocks.schema.schema as Schema
|
||||
serverMocks.schema.schema
|
||||
);
|
||||
crossfilter = new AnnoMatrixObsCrossfilter(annoMatrix);
|
||||
});
|
||||
@@ -73,11 +67,8 @@ describe("AnnoMatrixCrossfilter", () => {
|
||||
crossfilter.obsCrossfilter.hasDimension("obs/louvain")
|
||||
).toBeFalsy();
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS.
|
||||
(fetch as any).once(
|
||||
serverMocks.dataframeResponse(["louvain"], [obsLouvain])
|
||||
);
|
||||
let newCrossfilter = await crossfilter.select(Field.obs, "louvain", {
|
||||
fetch.once(serverMocks.dataframeResponse(["louvain"], [obsLouvain]));
|
||||
let newCrossfilter = await crossfilter.select("obs", "louvain", {
|
||||
mode: "none",
|
||||
});
|
||||
|
||||
@@ -85,10 +76,9 @@ describe("AnnoMatrixCrossfilter", () => {
|
||||
expect(
|
||||
newCrossfilter.obsCrossfilter.hasDimension("obs/louvain")
|
||||
).toBeTruthy();
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS.
|
||||
expect((fetch as any).mock.calls).toHaveLength(1);
|
||||
expect(fetch.mock.calls).toHaveLength(1);
|
||||
|
||||
newCrossfilter = await crossfilter.select(Field.obs, "louvain", {
|
||||
newCrossfilter = await crossfilter.select("obs", "louvain", {
|
||||
mode: "all",
|
||||
});
|
||||
expect(newCrossfilter.countSelected()).toEqual(annoMatrix.nObs);
|
||||
@@ -97,11 +87,8 @@ describe("AnnoMatrixCrossfilter", () => {
|
||||
test("simple column select", async () => {
|
||||
let xfltr;
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS.
|
||||
(fetch as any).once(
|
||||
serverMocks.dataframeResponse(["louvain"], [obsLouvain])
|
||||
);
|
||||
xfltr = await crossfilter.select(Field.obs, "louvain", {
|
||||
fetch.once(serverMocks.dataframeResponse(["louvain"], [obsLouvain]));
|
||||
xfltr = await crossfilter.select("obs", "louvain", {
|
||||
mode: "exact",
|
||||
values: ["NK cells", "B cells"],
|
||||
});
|
||||
@@ -118,7 +105,6 @@ describe("AnnoMatrixCrossfilter", () => {
|
||||
expect(xfltr.allSelectedLabels()).toEqual(
|
||||
Int32Array.from(
|
||||
obsLouvain.reduce((acc, val, idx) => {
|
||||
// @ts-expect-error ts-migrate(2345) FIXME: Argument of type 'number' is not assignable to par... Remove this comment to see the full error message
|
||||
if (val === "NK cells" || val === "B cells") acc.push(idx);
|
||||
return acc;
|
||||
}, [])
|
||||
@@ -134,20 +120,17 @@ describe("AnnoMatrixCrossfilter", () => {
|
||||
)
|
||||
);
|
||||
|
||||
const df: Dataframe = await annoMatrix.fetch(Field.obs, "louvain");
|
||||
const df = await annoMatrix.fetch("obs", "louvain");
|
||||
const values = df.col("louvain").asArray();
|
||||
const selected = xfltr.allSelectedMask();
|
||||
values.every(
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS.
|
||||
(val: any, idx: any) =>
|
||||
!["NK cells", "B cells"].includes(val) !== !selected[idx]
|
||||
(val, idx) => !["NK cells", "B cells"].includes(val) !== !selected[idx]
|
||||
);
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS.
|
||||
(fetch as any).once(
|
||||
fetch.once(
|
||||
serverMocks.dataframeResponse(["n_genes"], [new Int32Array(obsNGenes)])
|
||||
);
|
||||
xfltr = await xfltr.select(Field.obs, "n_genes", {
|
||||
xfltr = await xfltr.select("obs", "n_genes", {
|
||||
mode: "range",
|
||||
lo: 0,
|
||||
hi: 500,
|
||||
@@ -163,7 +146,6 @@ describe("AnnoMatrixCrossfilter", () => {
|
||||
val < 500 &&
|
||||
(louvain === "NK cells" || louvain === "B cells")
|
||||
)
|
||||
// @ts-expect-error ts-migrate(2345) FIXME: Argument of type 'number' is not assignable to par... Remove this comment to see the full error message
|
||||
acc.push(idx);
|
||||
return acc;
|
||||
}, [])
|
||||
@@ -178,8 +160,7 @@ describe("AnnoMatrixCrossfilter", () => {
|
||||
const varIndex = annoMatrix.schema.annotations.var.index;
|
||||
|
||||
const { nObs } = annoMatrix.schema.dataframe;
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS.
|
||||
(fetch as any).once(
|
||||
fetch.once(
|
||||
serverMocks.dataframeResponse(
|
||||
["TEST"],
|
||||
[rangeFill(new Float32Array(nObs), 0, 0.1)]
|
||||
@@ -215,19 +196,14 @@ describe("AnnoMatrixCrossfilter", () => {
|
||||
});
|
||||
const values = df.icol(0).asArray();
|
||||
const selected = xfltr.allSelectedMask();
|
||||
values.every(
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS.
|
||||
(val: any, idx: any) => !(val >= 0 && val <= 50) !== !selected[idx]
|
||||
values.every((val, idx) => !(val >= 0 && val <= 50) !== !selected[idx]);
|
||||
expect(selected.reduce((acc, val) => (val ? acc + 1 : acc), 0)).toEqual(
|
||||
xfltr.countSelected()
|
||||
);
|
||||
expect(
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS.
|
||||
selected.reduce((acc: any, val: any) => (val ? acc + 1 : acc), 0)
|
||||
).toEqual(xfltr.countSelected());
|
||||
});
|
||||
|
||||
test("spatial column select", async () => {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS.
|
||||
(fetch as any).once(
|
||||
fetch.once(
|
||||
serverMocks.dataframeResponse(
|
||||
["umap_0", "umap_1"],
|
||||
[Float32Array.from(embUmap[0]), Float32Array.from(embUmap[1])]
|
||||
@@ -246,7 +222,6 @@ describe("AnnoMatrixCrossfilter", () => {
|
||||
test("select on subset", async () => {
|
||||
const mask = new Uint8Array(annoMatrix.nObs).fill(0);
|
||||
for (let i = 0; i < mask.length; i += 2) {
|
||||
// @ts-expect-error ts-migrate(2322) FIXME: Type 'boolean' is not assignable to type 'number'.
|
||||
mask[i] = true;
|
||||
}
|
||||
const annoMatrixSubset = isubsetMask(annoMatrix, mask);
|
||||
@@ -255,11 +230,8 @@ describe("AnnoMatrixCrossfilter", () => {
|
||||
let xfltr = new AnnoMatrixObsCrossfilter(annoMatrixSubset);
|
||||
expect(xfltr.countSelected()).toEqual(annoMatrixSubset.nObs);
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS.
|
||||
(fetch as any).once(
|
||||
serverMocks.dataframeResponse(["louvain"], [obsLouvain])
|
||||
);
|
||||
xfltr = await xfltr.select(Field.obs, "louvain", {
|
||||
fetch.once(serverMocks.dataframeResponse(["louvain"], [obsLouvain]));
|
||||
xfltr = await xfltr.select("obs", "louvain", {
|
||||
mode: "exact",
|
||||
values: ["NK cells", "B cells"],
|
||||
});
|
||||
@@ -267,17 +239,11 @@ describe("AnnoMatrixCrossfilter", () => {
|
||||
expect(xfltr).toBeDefined();
|
||||
expect(xfltr.countSelected()).toEqual(240);
|
||||
|
||||
const df: Dataframe = (await annoMatrixSubset.fetch(
|
||||
Field.obs,
|
||||
"louvain"
|
||||
)) as Dataframe;
|
||||
expect(df).toBeDefined();
|
||||
const df = await annoMatrixSubset.fetch("obs", "louvain");
|
||||
const values = df.col("louvain").asArray();
|
||||
const selected = xfltr.allSelectedMask();
|
||||
values.every(
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS.
|
||||
(val: any, idx: any) =>
|
||||
!["NK cells", "B cells"].includes(val) !== !selected[idx]
|
||||
(val, idx) => !["NK cells", "B cells"].includes(val) !== !selected[idx]
|
||||
);
|
||||
});
|
||||
|
||||
@@ -290,9 +256,8 @@ describe("AnnoMatrixCrossfilter", () => {
|
||||
"unable to obsSelect upon the var dimension"
|
||||
);
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS.
|
||||
(fetch as any).mockRejectOnce(new Error("unknown column name"));
|
||||
await expect(crossfilter.select(Field.obs, "foo")).rejects.toThrow(
|
||||
fetch.mockRejectOnce(new Error("unknown column name"));
|
||||
await expect(crossfilter.select("obs", "foo")).rejects.toThrow(
|
||||
"unknown column name"
|
||||
);
|
||||
});
|
||||
@@ -302,32 +267,27 @@ describe("AnnoMatrixCrossfilter", () => {
|
||||
/*
|
||||
test the matrix mutators via crossfilter proxy
|
||||
*/
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS.
|
||||
async function helperAddTestCol(cf: any, colName: any, colSchema = null) {
|
||||
async function helperAddTestCol(cf, colName, colSchema = null) {
|
||||
expect(
|
||||
cf.annoMatrix.getMatrixColumns(Field.obs).includes(colName)
|
||||
cf.annoMatrix.getMatrixColumns("obs").includes(colName)
|
||||
).toBeFalsy();
|
||||
|
||||
if (colSchema === null) {
|
||||
// @ts-expect-error ts-migrate(2322) FIXME: Type '{ name: any; type: string; categories: strin... Remove this comment to see the full error message
|
||||
colSchema = {
|
||||
name: colName,
|
||||
type: "categorical",
|
||||
categories: ["toasty"],
|
||||
};
|
||||
}
|
||||
// @ts-expect-error ts-migrate(2531) FIXME: Object is possibly 'null'.
|
||||
colSchema.name = colName;
|
||||
// @ts-expect-error ts-migrate(2531) FIXME: Object is possibly 'null'.
|
||||
const initValue = colSchema.categories[0];
|
||||
const xfltr = cf.addObsColumn(colSchema, Array, initValue);
|
||||
expect(
|
||||
xfltr.annoMatrix.schema.annotations.obs.columns.filter(
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS.
|
||||
(v: any) => v.name === colName
|
||||
(v) => v.name === colName
|
||||
)
|
||||
).toHaveLength(1);
|
||||
const df = await xfltr.annoMatrix.fetch(Field.obs, colName);
|
||||
const df = await xfltr.annoMatrix.fetch("obs", colName);
|
||||
expect(df.hasCol(colName)).toBeTruthy();
|
||||
return xfltr;
|
||||
}
|
||||
@@ -335,7 +295,7 @@ describe("AnnoMatrixCrossfilter", () => {
|
||||
test("addObsColumn", async () => {
|
||||
expect(crossfilter.countSelected()).toBe(annoMatrix.nObs);
|
||||
expect(
|
||||
crossfilter.annoMatrix.getMatrixColumns(Field.obs).includes("foo")
|
||||
crossfilter.annoMatrix.getMatrixColumns("obs").includes("foo")
|
||||
).toBeFalsy();
|
||||
const xfltr = crossfilter.addObsColumn(
|
||||
{ name: "foo", type: "categorical", categories: ["A"] },
|
||||
@@ -346,7 +306,7 @@ describe("AnnoMatrixCrossfilter", () => {
|
||||
// check schema updates correctly.
|
||||
expect(xfltr.countSelected()).toBe(annoMatrix.nObs);
|
||||
expect(
|
||||
xfltr.annoMatrix.getMatrixColumns(Field.obs).includes("foo")
|
||||
xfltr.annoMatrix.getMatrixColumns("obs").includes("foo")
|
||||
).toBeTruthy();
|
||||
expect(xfltr.annoMatrix.schema.annotations.obsByName.foo).toMatchObject({
|
||||
name: "foo",
|
||||
@@ -354,18 +314,17 @@ describe("AnnoMatrixCrossfilter", () => {
|
||||
});
|
||||
expect(
|
||||
xfltr.annoMatrix.schema.annotations.obs.columns.filter(
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS.
|
||||
(v: any) => v.name === "foo"
|
||||
(v) => v.name === "foo"
|
||||
)
|
||||
).toHaveLength(1);
|
||||
|
||||
// check data update.
|
||||
const df: Dataframe = await xfltr.annoMatrix.fetch(Field.obs, "foo");
|
||||
const df = await xfltr.annoMatrix.fetch("obs", "foo");
|
||||
expect(
|
||||
df
|
||||
.col("foo")
|
||||
.asArray() // eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS.
|
||||
.every((v: any) => v === "A")
|
||||
.asArray()
|
||||
.every((v) => v === "A")
|
||||
).toBeTruthy();
|
||||
|
||||
// check that we catch dups
|
||||
@@ -402,30 +361,27 @@ describe("AnnoMatrixCrossfilter", () => {
|
||||
xfltr = xfltr.dropObsColumn("foo");
|
||||
expect(
|
||||
xfltr.annoMatrix.schema.annotations.obs.columns.filter(
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS.
|
||||
(v: any) => v.name === "foo"
|
||||
(v) => v.name === "foo"
|
||||
)
|
||||
).toHaveLength(0);
|
||||
expect(xfltr.annoMatrix.schema.annotations.obsByName.foo).toBeUndefined();
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS.
|
||||
(fetch as any).mockRejectOnce(new Error("unknown column name"));
|
||||
await expect(xfltr.annoMatrix.fetch(Field.obs, "foo")).rejects.toThrow(
|
||||
fetch.mockRejectOnce(new Error("unknown column name"));
|
||||
await expect(xfltr.annoMatrix.fetch("obs", "foo")).rejects.toThrow(
|
||||
"unknown column name"
|
||||
);
|
||||
|
||||
// now same, but ensure we have built an index before doing the drop
|
||||
xfltr = await helperAddTestCol(crossfilter, "bar");
|
||||
xfltr = await xfltr.select(Field.obs, "bar", {
|
||||
xfltr = await xfltr.select("obs", "bar", {
|
||||
mode: "exact",
|
||||
values: "whatever",
|
||||
});
|
||||
xfltr = xfltr.dropObsColumn("bar");
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS.
|
||||
(fetch as any).mockRejectOnce(new Error("unknown column name"));
|
||||
await expect(
|
||||
xfltr.select(Field.obs, "bar", { mode: "all" })
|
||||
).rejects.toThrow("unknown column name");
|
||||
fetch.mockRejectOnce(new Error("unknown column name"));
|
||||
await expect(xfltr.select("obs", "bar", { mode: "all" })).rejects.toThrow(
|
||||
"unknown column name"
|
||||
);
|
||||
});
|
||||
|
||||
test("renameObsColumn", async () => {
|
||||
@@ -442,43 +398,38 @@ describe("AnnoMatrixCrossfilter", () => {
|
||||
// add a column, then rename it.
|
||||
xfltr = await helperAddTestCol(crossfilter, "foo");
|
||||
xfltr = xfltr.renameObsColumn("foo", "bar");
|
||||
expect(
|
||||
xfltr.annoMatrix.getColumnSchema(Field.obs, "foo")
|
||||
).toBeUndefined();
|
||||
expect(xfltr.annoMatrix.getColumnSchema(Field.obs, "bar")).toMatchObject({
|
||||
expect(xfltr.annoMatrix.getColumnSchema("obs", "foo")).toBeUndefined();
|
||||
expect(xfltr.annoMatrix.getColumnSchema("obs", "bar")).toMatchObject({
|
||||
name: "bar",
|
||||
type: "categorical",
|
||||
});
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS.
|
||||
(fetch as any).mockRejectOnce(new Error("unknown column name"));
|
||||
await expect(xfltr.annoMatrix.fetch(Field.obs, "foo")).rejects.toThrow(
|
||||
fetch.mockRejectOnce(new Error("unknown column name"));
|
||||
await expect(xfltr.annoMatrix.fetch("obs", "foo")).rejects.toThrow(
|
||||
"unknown column name"
|
||||
);
|
||||
const df = await xfltr.annoMatrix.fetch(Field.obs, "bar");
|
||||
const df = await xfltr.annoMatrix.fetch("obs", "bar");
|
||||
expect(df.hasCol("bar")).toBeTruthy();
|
||||
|
||||
// now same, but ensure we have built an index before doing the rename
|
||||
xfltr = await helperAddTestCol(crossfilter, "bar");
|
||||
xfltr = await xfltr.select(Field.obs, "bar", {
|
||||
xfltr = await xfltr.select("obs", "bar", {
|
||||
mode: "exact",
|
||||
values: "whatever",
|
||||
});
|
||||
xfltr = xfltr.renameObsColumn("bar", "xyz");
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS.
|
||||
(fetch as any).mockRejectOnce(new Error("unknown column name"));
|
||||
fetch.mockRejectOnce(new Error("unknown column name"));
|
||||
await expect(xfltr.select("obs", "bar", { mode: "all" })).rejects.toThrow(
|
||||
"unknown column name"
|
||||
);
|
||||
await expect(
|
||||
xfltr.select(Field.obs, "bar", { mode: "all" })
|
||||
).rejects.toThrow("unknown column name");
|
||||
await expect(
|
||||
xfltr.select(Field.obs, "xyz", { mode: "none" })
|
||||
xfltr.select("obs", "xyz", { mode: "none" })
|
||||
).resolves.toBeInstanceOf(AnnoMatrixObsCrossfilter);
|
||||
});
|
||||
|
||||
test("addObsAnnoCategory", async () => {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS.
|
||||
let xfltr: any;
|
||||
let xfltr;
|
||||
|
||||
// catch unknown or readonly columns
|
||||
expect(() => crossfilter.addObsAnnoCategory("louvain", "mumble")).toThrow(
|
||||
@@ -489,14 +440,13 @@ describe("AnnoMatrixCrossfilter", () => {
|
||||
).toThrow("Unknown or readonly obs column");
|
||||
|
||||
// add a column and then add category to it
|
||||
// @ts-expect-error ts-migrate(2345) FIXME: Argument of type '{ name: string; type: string; ca... Remove this comment to see the full error message
|
||||
xfltr = await helperAddTestCol(crossfilter, "foo", {
|
||||
name: "foo",
|
||||
type: "categorical",
|
||||
categories: ["unassigned"],
|
||||
});
|
||||
xfltr = xfltr.addObsAnnoCategory("foo", "a-new-label");
|
||||
expect(xfltr.annoMatrix.getColumnSchema(Field.obs, "foo")).toMatchObject({
|
||||
expect(xfltr.annoMatrix.getColumnSchema("obs", "foo")).toMatchObject({
|
||||
name: "foo",
|
||||
type: "categorical",
|
||||
categories: expect.arrayContaining(["a-new-label", "unassigned"]),
|
||||
@@ -508,18 +458,17 @@ describe("AnnoMatrixCrossfilter", () => {
|
||||
);
|
||||
|
||||
// now same, but ensure we have built an index before doing the operation
|
||||
// @ts-expect-error ts-migrate(2345) FIXME: Argument of type '{ name: string; type: string; ca... Remove this comment to see the full error message
|
||||
xfltr = await helperAddTestCol(crossfilter, "bar", {
|
||||
name: "bar",
|
||||
type: "categorical",
|
||||
categories: ["unassigned"],
|
||||
});
|
||||
xfltr = await xfltr.select(Field.obs, "bar", {
|
||||
xfltr = await xfltr.select("obs", "bar", {
|
||||
mode: "exact",
|
||||
values: "something",
|
||||
});
|
||||
xfltr = xfltr.addObsAnnoCategory("bar", "a-new-label");
|
||||
expect(xfltr.annoMatrix.getColumnSchema(Field.obs, "bar")).toMatchObject({
|
||||
expect(xfltr.annoMatrix.getColumnSchema("obs", "bar")).toMatchObject({
|
||||
name: "bar",
|
||||
type: "categorical",
|
||||
categories: expect.arrayContaining(["a-new-label", "unassigned"]),
|
||||
@@ -537,20 +486,19 @@ describe("AnnoMatrixCrossfilter", () => {
|
||||
crossfilter.removeObsAnnoCategory("undefined-name", "mumble")
|
||||
).rejects.toThrow("Unknown or readonly obs column");
|
||||
|
||||
// @ts-expect-error ts-migrate(2345) FIXME: Argument of type '{ name: string; type: string; ca... Remove this comment to see the full error message
|
||||
xfltr = await helperAddTestCol(crossfilter, "foo", {
|
||||
name: "foo",
|
||||
type: "categorical",
|
||||
categories: ["unassigned", "red", "green", "blue"],
|
||||
});
|
||||
xfltr = await xfltr.select(Field.obs, "foo", { mode: "all" });
|
||||
xfltr = await xfltr.select("obs", "foo", { mode: "all" });
|
||||
expect(
|
||||
(await xfltr.annoMatrix.fetch(Field.obs, "foo"))
|
||||
(await xfltr.annoMatrix.fetch("obs", "foo"))
|
||||
.col("foo")
|
||||
.asArray() // eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS.
|
||||
.every((v: any) => v === "unassigned")
|
||||
.asArray()
|
||||
.every((v) => v === "unassigned")
|
||||
).toBeTruthy();
|
||||
expect(xfltr.annoMatrix.getColumnSchema(Field.obs, "foo")).toMatchObject({
|
||||
expect(xfltr.annoMatrix.getColumnSchema("obs", "foo")).toMatchObject({
|
||||
name: "foo",
|
||||
type: "categorical",
|
||||
categories: expect.arrayContaining([
|
||||
@@ -564,23 +512,21 @@ describe("AnnoMatrixCrossfilter", () => {
|
||||
// remove an unused category
|
||||
const xfltr1 = await xfltr.removeObsAnnoCategory("foo", "red", "mumble");
|
||||
expect(
|
||||
(await xfltr1.annoMatrix.fetch(Field.obs, "foo"))
|
||||
(await xfltr1.annoMatrix.fetch("obs", "foo"))
|
||||
.col("foo")
|
||||
.asArray() // eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS.
|
||||
.every((v: any) => v === "unassigned")
|
||||
.asArray()
|
||||
.every((v) => v === "unassigned")
|
||||
).toBeTruthy();
|
||||
expect(xfltr1.annoMatrix.getColumnSchema(Field.obs, "foo")).toMatchObject(
|
||||
{
|
||||
name: "foo",
|
||||
type: "categorical",
|
||||
categories: expect.arrayContaining([
|
||||
"unassigned",
|
||||
"green",
|
||||
"blue",
|
||||
"mumble",
|
||||
]),
|
||||
}
|
||||
);
|
||||
expect(xfltr1.annoMatrix.getColumnSchema("obs", "foo")).toMatchObject({
|
||||
name: "foo",
|
||||
type: "categorical",
|
||||
categories: expect.arrayContaining([
|
||||
"unassigned",
|
||||
"green",
|
||||
"blue",
|
||||
"mumble",
|
||||
]),
|
||||
});
|
||||
|
||||
// remove a used category
|
||||
const xfltr2 = await xfltr.removeObsAnnoCategory(
|
||||
@@ -589,18 +535,16 @@ describe("AnnoMatrixCrossfilter", () => {
|
||||
"red"
|
||||
);
|
||||
expect(
|
||||
(await xfltr2.annoMatrix.fetch(Field.obs, "foo"))
|
||||
(await xfltr2.annoMatrix.fetch("obs", "foo"))
|
||||
.col("foo")
|
||||
.asArray() // eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS.
|
||||
.every((v: any) => v === "red")
|
||||
.asArray()
|
||||
.every((v) => v === "red")
|
||||
).toBeTruthy();
|
||||
expect(xfltr2.annoMatrix.getColumnSchema(Field.obs, "foo")).toMatchObject(
|
||||
{
|
||||
name: "foo",
|
||||
type: "categorical",
|
||||
categories: expect.arrayContaining(["green", "blue", "red"]),
|
||||
}
|
||||
);
|
||||
expect(xfltr2.annoMatrix.getColumnSchema("obs", "foo")).toMatchObject({
|
||||
name: "foo",
|
||||
type: "categorical",
|
||||
categories: expect.arrayContaining(["green", "blue", "red"]),
|
||||
});
|
||||
});
|
||||
|
||||
test("setObsColumnValues", async () => {
|
||||
@@ -612,13 +556,12 @@ describe("AnnoMatrixCrossfilter", () => {
|
||||
crossfilter.setObsColumnValues("undefined-name", [0], "mumble")
|
||||
).rejects.toThrow("Unknown or readonly obs column");
|
||||
|
||||
// @ts-expect-error ts-migrate(2345) FIXME: Argument of type '{ name: string; type: string; ca... Remove this comment to see the full error message
|
||||
let xfltr = await helperAddTestCol(crossfilter, "foo", {
|
||||
name: "foo",
|
||||
type: "categorical",
|
||||
categories: ["unassigned", "red", "green", "blue"],
|
||||
});
|
||||
xfltr = await xfltr.select(Field.obs, "foo", { mode: "all" });
|
||||
xfltr = await xfltr.select("obs", "foo", { mode: "all" });
|
||||
|
||||
// catch unknown row label
|
||||
await expect(() =>
|
||||
@@ -627,43 +570,40 @@ describe("AnnoMatrixCrossfilter", () => {
|
||||
|
||||
// set a few rows
|
||||
expect(
|
||||
(await xfltr.annoMatrix.fetch(Field.obs, "foo"))
|
||||
(await xfltr.annoMatrix.fetch("obs", "foo"))
|
||||
.col("foo")
|
||||
.asArray() // eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS.
|
||||
.every((v: any) => v === "unassigned")
|
||||
.asArray()
|
||||
.every((v) => v === "unassigned")
|
||||
).toBeTruthy();
|
||||
const xfltr1 = await xfltr.setObsColumnValues("foo", [0, 10], "purple");
|
||||
expect(
|
||||
(await xfltr1.annoMatrix.fetch(Field.obs, "foo"))
|
||||
(await xfltr1.annoMatrix.fetch("obs", "foo"))
|
||||
.col("foo")
|
||||
.asArray()
|
||||
.every(
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS.
|
||||
(v: any, i: any) =>
|
||||
(v, i) =>
|
||||
v === "unassigned" || (v === "purple" && (i === 0 || i === 10))
|
||||
)
|
||||
).toBeTruthy();
|
||||
expect(xfltr1.annoMatrix.getColumnSchema(Field.obs, "foo")).toMatchObject(
|
||||
{
|
||||
name: "foo",
|
||||
type: "categorical",
|
||||
categories: expect.arrayContaining([
|
||||
"unassigned",
|
||||
"red",
|
||||
"green",
|
||||
"blue",
|
||||
"purple",
|
||||
]),
|
||||
}
|
||||
);
|
||||
expect(xfltr1.annoMatrix.getColumnSchema("obs", "foo")).toMatchObject({
|
||||
name: "foo",
|
||||
type: "categorical",
|
||||
categories: expect.arrayContaining([
|
||||
"unassigned",
|
||||
"red",
|
||||
"green",
|
||||
"blue",
|
||||
"purple",
|
||||
]),
|
||||
});
|
||||
|
||||
expect(xfltr1.countSelected()).toEqual(xfltr1.annoMatrix.nObs);
|
||||
const xfltr2 = await xfltr1.select(Field.obs, "foo", {
|
||||
const xfltr2 = await xfltr1.select("obs", "foo", {
|
||||
mode: "exact",
|
||||
values: ["purple"],
|
||||
});
|
||||
expect(xfltr2.countSelected()).toEqual(2);
|
||||
expect(xfltr2.allSelectedLabels()).toEqual(Array.from([0, 10]));
|
||||
expect(xfltr2.allSelectedLabels()).toEqual(Int32Array.from([0, 10]));
|
||||
});
|
||||
|
||||
test("resetObsColumnValues", async () => {
|
||||
@@ -675,13 +615,12 @@ describe("AnnoMatrixCrossfilter", () => {
|
||||
crossfilter.resetObsColumnValues("undefined-name", "red", "blue")
|
||||
).rejects.toThrow("Unknown or readonly obs column");
|
||||
|
||||
// @ts-expect-error ts-migrate(2345) FIXME: Argument of type '{ name: string; type: string; ca... Remove this comment to see the full error message
|
||||
let xfltr = await helperAddTestCol(crossfilter, "foo", {
|
||||
name: "foo",
|
||||
type: "categorical",
|
||||
categories: ["unassigned", "red", "green", "blue"],
|
||||
});
|
||||
xfltr = await xfltr.select(Field.obs, "foo", {
|
||||
xfltr = await xfltr.select("obs", "foo", {
|
||||
mode: "exact",
|
||||
values: "red",
|
||||
});
|
||||
@@ -692,60 +631,54 @@ describe("AnnoMatrixCrossfilter", () => {
|
||||
).rejects.toThrow("unknown category");
|
||||
|
||||
let xfltr1 = await xfltr.setObsColumnValues("foo", [0, 10], "purple");
|
||||
xfltr1 = await xfltr1.select(Field.obs, "foo", {
|
||||
xfltr1 = await xfltr1.select("obs", "foo", {
|
||||
mode: "exact",
|
||||
values: "purple",
|
||||
});
|
||||
expect(
|
||||
(await xfltr1.annoMatrix.fetch(Field.obs, "foo"))
|
||||
(await xfltr1.annoMatrix.fetch("obs", "foo"))
|
||||
.col("foo")
|
||||
.asArray() // eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS.
|
||||
.filter((v: any) => v === "purple")
|
||||
.asArray()
|
||||
.filter((v) => v === "purple")
|
||||
).toHaveLength(2);
|
||||
|
||||
xfltr1 = await xfltr1.resetObsColumnValues("foo", "purple", "magenta");
|
||||
expect(
|
||||
(await xfltr1.annoMatrix.fetch(Field.obs, "foo"))
|
||||
(await xfltr1.annoMatrix.fetch("obs", "foo"))
|
||||
.col("foo")
|
||||
.asArray() // eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS.
|
||||
.filter((v: any) => v === "magenta")
|
||||
.asArray()
|
||||
.filter((v) => v === "magenta")
|
||||
).toHaveLength(2);
|
||||
expect(
|
||||
(await xfltr1.annoMatrix.fetch(Field.obs, "foo"))
|
||||
(await xfltr1.annoMatrix.fetch("obs", "foo"))
|
||||
.col("foo")
|
||||
.asArray() // eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS.
|
||||
.filter((v: any) => v === "purple")
|
||||
.asArray()
|
||||
.filter((v) => v === "purple")
|
||||
).toHaveLength(0);
|
||||
expect(xfltr1.annoMatrix.getColumnSchema(Field.obs, "foo")).toMatchObject(
|
||||
{
|
||||
name: "foo",
|
||||
type: "categorical",
|
||||
categories: expect.arrayContaining([
|
||||
"unassigned",
|
||||
"red",
|
||||
"green",
|
||||
"blue",
|
||||
"purple",
|
||||
"magenta",
|
||||
]),
|
||||
}
|
||||
);
|
||||
expect(xfltr1.annoMatrix.getColumnSchema("obs", "foo")).toMatchObject({
|
||||
name: "foo",
|
||||
type: "categorical",
|
||||
categories: expect.arrayContaining([
|
||||
"unassigned",
|
||||
"red",
|
||||
"green",
|
||||
"blue",
|
||||
"purple",
|
||||
"magenta",
|
||||
]),
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("edge cases", () => {
|
||||
test("transition from empty annoMatrix", async () => {
|
||||
// select before fetch needs to work
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS.
|
||||
(fetch as any).once(
|
||||
serverMocks.dataframeResponse(["louvain"], [obsLouvain])
|
||||
);
|
||||
const xfltr = await crossfilter.select(Field.obs, "louvain", {
|
||||
fetch.once(serverMocks.dataframeResponse(["louvain"], [obsLouvain]));
|
||||
const xfltr = await crossfilter.select("obs", "louvain", {
|
||||
mode: "exact",
|
||||
values: "B cells",
|
||||
});
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS.
|
||||
expect((fetch as any).mock.calls).toHaveLength(1);
|
||||
expect(fetch.mock.calls).toHaveLength(1);
|
||||
expect(xfltr.obsCrossfilter.hasDimension("obs/louvain")).toBeTruthy();
|
||||
expect(xfltr.obsCrossfilter.all()).toBe(xfltr.annoMatrix._cache.obs);
|
||||
expect(xfltr.countSelected()).toEqual(
|
||||
File diff suppressed because it is too large
Load Diff
+1
-2
@@ -1,7 +1,6 @@
|
||||
export const baseDataURL = "https://a.fake.url/api/v0.2";
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS.
|
||||
(window as any).CELLXGENE = {
|
||||
window.CELLXGENE = {
|
||||
API: {
|
||||
prefix: baseDataURL,
|
||||
version: "v0.2/",
|
||||
@@ -0,0 +1,211 @@
|
||||
import { schema } from "./schema";
|
||||
import { Dataframe, KeyIndex } from "../../../../src/util/dataframe";
|
||||
import { encodeMatrixFBS } from "../../../../src/util/stateManager/matrix";
|
||||
|
||||
const indexedSchema = {
|
||||
obsByName: Object.fromEntries(
|
||||
schema.schema.annotations.obs.columns.map((v) => [v.name, v]) ?? []
|
||||
),
|
||||
varByName: Object.fromEntries(
|
||||
schema.schema.annotations.var.columns.map((v) => [v.name, v]) ?? []
|
||||
),
|
||||
embByName: Object.fromEntries(
|
||||
schema.schema.layout.obs.map((v) => [v.name, v]) ?? []
|
||||
),
|
||||
};
|
||||
|
||||
function makeMockColumn(s, length) {
|
||||
const { type } = s;
|
||||
switch (type) {
|
||||
case "int32":
|
||||
return new Int32Array(length).fill(Math.floor(99 * Math.random()));
|
||||
|
||||
case "string":
|
||||
return new Array(length).fill("test");
|
||||
|
||||
case "float32":
|
||||
return new Float32Array(length).fill(99 * Math.random());
|
||||
|
||||
case "boolean":
|
||||
return new Array(length).fill(false);
|
||||
|
||||
case "categorical":
|
||||
return new Array(length).fill(s.categories[0]);
|
||||
|
||||
default:
|
||||
throw new Error("unkonwn type");
|
||||
}
|
||||
}
|
||||
|
||||
function getEncodedDataframe(colNames, length, colSchemas) {
|
||||
const colIndex = new KeyIndex(colNames);
|
||||
const columns = colSchemas.map((s) => makeMockColumn(s, length));
|
||||
const df = new Dataframe([length, colNames.length], columns, null, colIndex);
|
||||
const body = encodeMatrixFBS(df);
|
||||
return body;
|
||||
}
|
||||
|
||||
export function dataframeResponse(colNames, columns) {
|
||||
const colIndex = new KeyIndex(colNames);
|
||||
const df = new Dataframe(
|
||||
[columns[0].length, colNames.length],
|
||||
columns,
|
||||
null,
|
||||
colIndex
|
||||
);
|
||||
const body = encodeMatrixFBS(df);
|
||||
const headers = new Headers({
|
||||
"Content-Type": "application/octet-stream",
|
||||
});
|
||||
return () => Promise.resolve({ body, init: { status: 200, headers } });
|
||||
}
|
||||
|
||||
function annotationObsResponse(request) {
|
||||
const url = new URL(request.url);
|
||||
const params = Array.from(url.searchParams.entries());
|
||||
const names = params
|
||||
.filter(([k]) => k === "annotation-name")
|
||||
.map(([, v]) => v);
|
||||
if (!names.every((n) => indexedSchema.obsByName[n])) {
|
||||
return Promise.reject(new Error("bad obs annotation name in URL"));
|
||||
}
|
||||
const colSchemas = names.map((n) => indexedSchema.obsByName[n]);
|
||||
const body = getEncodedDataframe(
|
||||
names,
|
||||
schema.schema.dataframe.nObs,
|
||||
colSchemas
|
||||
);
|
||||
|
||||
const headers = new Headers({
|
||||
"Content-Type": "application/octet-stream",
|
||||
});
|
||||
return Promise.resolve({
|
||||
body,
|
||||
init: { status: 200, headers },
|
||||
});
|
||||
}
|
||||
|
||||
function annotationVarResponse(request) {
|
||||
const url = new URL(request.url);
|
||||
const params = Array.from(url.searchParams.entries());
|
||||
const names = params
|
||||
.filter(([k]) => k === "annotation-name")
|
||||
.map(([, v]) => v);
|
||||
if (!names.every((n) => indexedSchema.varByName[n])) {
|
||||
return Promise.reject(new Error("bad var annotation name in URL"));
|
||||
}
|
||||
const colSchemas = names.map((n) => indexedSchema.varByName[n]);
|
||||
const body = getEncodedDataframe(
|
||||
names,
|
||||
schema.schema.dataframe.nVar,
|
||||
colSchemas
|
||||
);
|
||||
|
||||
const headers = new Headers({
|
||||
"Content-Type": "application/octet-stream",
|
||||
});
|
||||
return Promise.resolve({
|
||||
body,
|
||||
init: { status: 200, headers },
|
||||
});
|
||||
}
|
||||
|
||||
function layoutObsResponse(request) {
|
||||
const url = new URL(request.url);
|
||||
const params = Array.from(url.searchParams.entries());
|
||||
const names = params.filter(([k]) => k === "layout-name").map(([, v]) => v);
|
||||
if (!names.every((n) => indexedSchema.embByName[n])) {
|
||||
return Promise.reject(new Error("bad layout name in URL"));
|
||||
}
|
||||
const dims = names.map((n) => indexedSchema.embByName[n].dims).flat();
|
||||
const colSchemas = names
|
||||
.map((n) => [indexedSchema.embByName[n], indexedSchema.embByName[n]])
|
||||
.flat();
|
||||
const body = getEncodedDataframe(
|
||||
dims,
|
||||
schema.schema.dataframe.nObs,
|
||||
colSchemas
|
||||
);
|
||||
|
||||
const headers = new Headers({
|
||||
"Content-Type": "application/octet-stream",
|
||||
});
|
||||
return Promise.resolve({
|
||||
body,
|
||||
init: { status: 200, headers },
|
||||
});
|
||||
}
|
||||
|
||||
function dataVarResponse(request) {
|
||||
const url = new URL(request.url);
|
||||
const params = Array.from(url.searchParams.entries());
|
||||
|
||||
const colNames = params.map((v) => `${v[0]}/${v[1]}`);
|
||||
const colSchemas = colNames.map(() => schema.schema.dataframe);
|
||||
const body = getEncodedDataframe(
|
||||
colNames,
|
||||
schema.schema.dataframe.nObs,
|
||||
colSchemas
|
||||
);
|
||||
|
||||
const headers = new Headers({
|
||||
"Content-Type": "application/octet-stream",
|
||||
});
|
||||
return Promise.resolve({
|
||||
body,
|
||||
init: { status: 200, headers },
|
||||
});
|
||||
}
|
||||
|
||||
export function responder(request) {
|
||||
const url = new URL(request.url);
|
||||
const { pathname } = url;
|
||||
if (pathname.endsWith("/annotations/obs")) {
|
||||
return annotationObsResponse(request);
|
||||
}
|
||||
if (pathname.endsWith("/annotations/var")) {
|
||||
return annotationVarResponse(request);
|
||||
}
|
||||
if (pathname.endsWith("/layout/obs")) {
|
||||
return layoutObsResponse(request);
|
||||
}
|
||||
if (pathname.endsWith("/data/var")) {
|
||||
return dataVarResponse(request);
|
||||
}
|
||||
return Promise.reject(new Error("bad URL"));
|
||||
}
|
||||
|
||||
export function withExpected(expectedURL, expectedParams) {
|
||||
/*
|
||||
Do some additional error checking
|
||||
*/
|
||||
return (request) => {
|
||||
// if URL is bogus, reject the promise
|
||||
const url = new URL(request.url);
|
||||
if (!url.pathname.endsWith(expectedURL)) {
|
||||
return Promise.reject(new Error("Unexpected URL!"));
|
||||
}
|
||||
const params = Array.from(url.searchParams.entries()).sort(
|
||||
(a, b) => a[0] < b[0]
|
||||
);
|
||||
expectedParams = expectedParams.slice().sort((a, b) => a[0] < b[0]);
|
||||
|
||||
if (
|
||||
params.length !== expectedParams.length ||
|
||||
!params.every(
|
||||
(p, i) => p[0] === expectedParams[i][0] && p[1] === expectedParams[i][1]
|
||||
)
|
||||
) {
|
||||
return Promise.reject(new Error("unexpected name requested in URL"));
|
||||
}
|
||||
|
||||
return responder(request);
|
||||
};
|
||||
}
|
||||
|
||||
export function annotationsObs(names) {
|
||||
return withExpected(
|
||||
"/annotations/obs",
|
||||
names.map((name) => ["annotation-name", name])
|
||||
);
|
||||
}
|
||||
@@ -1,249 +0,0 @@
|
||||
import { schema } from "./schema";
|
||||
import { Dataframe, KeyIndex } from "../../../../src/util/dataframe";
|
||||
import { encodeMatrixFBS } from "../../../../src/util/stateManager/matrix";
|
||||
|
||||
const indexedSchema = {
|
||||
obsByName: Object.fromEntries(
|
||||
schema.schema.annotations.obs.columns.map((v) => [v.name, v]) ?? []
|
||||
),
|
||||
varByName: Object.fromEntries(
|
||||
schema.schema.annotations.var.columns.map((v) => [v.name, v]) ?? []
|
||||
),
|
||||
embByName: Object.fromEntries(
|
||||
schema.schema.layout.obs.map((v) => [v.name, v]) ?? []
|
||||
),
|
||||
};
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS.
|
||||
function makeMockColumn(s: any, length: any) {
|
||||
const { type } = s;
|
||||
switch (type) {
|
||||
case "int32":
|
||||
return new Int32Array(length).fill(Math.floor(99 * Math.random()));
|
||||
|
||||
case "string":
|
||||
return new Array(length).fill("test");
|
||||
|
||||
case "float32":
|
||||
return new Float32Array(length).fill(99 * Math.random());
|
||||
|
||||
case "boolean":
|
||||
return new Array(length).fill(false);
|
||||
|
||||
case "categorical":
|
||||
return new Array(length).fill(s.categories[0]);
|
||||
|
||||
default:
|
||||
throw new Error("unknown type");
|
||||
}
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS.
|
||||
function getEncodedDataframe(colNames: any, length: any, colSchemas: any) {
|
||||
const colIndex = new KeyIndex(colNames);
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS.
|
||||
const columns = colSchemas.map((s: any) => makeMockColumn(s, length));
|
||||
const df = new Dataframe([length, colNames.length], columns, null, colIndex);
|
||||
const body = encodeMatrixFBS(df);
|
||||
return body;
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any -- - FIXME: disabled temporarily on migrate to TS.
|
||||
export function dataframeResponse(colNames: any, columns: any) {
|
||||
const colIndex = new KeyIndex(colNames);
|
||||
const df = new Dataframe(
|
||||
[columns[0].length, colNames.length],
|
||||
columns,
|
||||
null,
|
||||
colIndex
|
||||
);
|
||||
const body = encodeMatrixFBS(df);
|
||||
const headers = new Headers({
|
||||
"Content-Type": "application/octet-stream",
|
||||
});
|
||||
return () => Promise.resolve({ body, init: { status: 200, headers } });
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS.
|
||||
function annotationObsResponse(request: any) {
|
||||
const url = new URL(request.url);
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS.
|
||||
const params = Array.from((url.searchParams as any).entries());
|
||||
const names = params
|
||||
// @ts-expect-error ts-migrate(2769) FIXME: No overload matches this call.
|
||||
.filter(([k]) => k === "annotation-name")
|
||||
// @ts-expect-error ts-migrate(2345) FIXME: Argument of type '([, v]: [any, any]) => any' is n... Remove this comment to see the full error message
|
||||
.map(([, v]) => v);
|
||||
// @ts-expect-error ts-migrate(2538) FIXME: Type 'unknown' cannot be used as an index type.
|
||||
if (!names.every((n) => indexedSchema.obsByName[n])) {
|
||||
return Promise.reject(new Error("bad obs annotation name in URL"));
|
||||
}
|
||||
// @ts-expect-error ts-migrate(2538) FIXME: Type 'unknown' cannot be used as an index type.
|
||||
const colSchemas = names.map((n) => indexedSchema.obsByName[n]);
|
||||
const body = getEncodedDataframe(
|
||||
names,
|
||||
schema.schema.dataframe.nObs,
|
||||
colSchemas
|
||||
);
|
||||
|
||||
const headers = new Headers({
|
||||
"Content-Type": "application/octet-stream",
|
||||
});
|
||||
return Promise.resolve({
|
||||
body,
|
||||
init: { status: 200, headers },
|
||||
});
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS.
|
||||
function annotationVarResponse(request: any) {
|
||||
const url = new URL(request.url);
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS.
|
||||
const params = Array.from((url.searchParams as any).entries());
|
||||
const names = params
|
||||
// @ts-expect-error ts-migrate(2769) FIXME: No overload matches this call.
|
||||
.filter(([k]) => k === "annotation-name")
|
||||
// @ts-expect-error ts-migrate(2345) FIXME: Argument of type '([, v]: [any, any]) => any' is n... Remove this comment to see the full error message
|
||||
.map(([, v]) => v);
|
||||
// @ts-expect-error ts-migrate(2538) FIXME: Type 'unknown' cannot be used as an index type.
|
||||
if (!names.every((n) => indexedSchema.varByName[n])) {
|
||||
return Promise.reject(new Error("bad var annotation name in URL"));
|
||||
}
|
||||
// @ts-expect-error ts-migrate(2538) FIXME: Type 'unknown' cannot be used as an index type.
|
||||
const colSchemas = names.map((n) => indexedSchema.varByName[n]);
|
||||
const body = getEncodedDataframe(
|
||||
names,
|
||||
schema.schema.dataframe.nVar,
|
||||
colSchemas
|
||||
);
|
||||
|
||||
const headers = new Headers({
|
||||
"Content-Type": "application/octet-stream",
|
||||
});
|
||||
return Promise.resolve({
|
||||
body,
|
||||
init: { status: 200, headers },
|
||||
});
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS.
|
||||
function layoutObsResponse(request: any) {
|
||||
const url = new URL(request.url);
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS.
|
||||
const params = Array.from((url.searchParams as any).entries());
|
||||
// @ts-expect-error ts-migrate(2769) FIXME: No overload matches this call.
|
||||
const names = params.filter(([k]) => k === "layout-name").map(([, v]) => v);
|
||||
// @ts-expect-error ts-migrate(2538) FIXME: Type 'unknown' cannot be used as an index type.
|
||||
if (!names.every((n) => indexedSchema.embByName[n])) {
|
||||
return Promise.reject(new Error("bad layout name in URL"));
|
||||
}
|
||||
// @ts-expect-error ts-migrate(2538) FIXME: Type 'unknown' cannot be used as an index type.
|
||||
const dims = names.map((n) => indexedSchema.embByName[n].dims).flat();
|
||||
const colSchemas = names
|
||||
// @ts-expect-error ts-migrate(2538) FIXME: Type 'unknown' cannot be used as an index type.
|
||||
.map((n) => [indexedSchema.embByName[n], indexedSchema.embByName[n]])
|
||||
.flat();
|
||||
const body = getEncodedDataframe(
|
||||
dims,
|
||||
schema.schema.dataframe.nObs,
|
||||
colSchemas
|
||||
);
|
||||
|
||||
const headers = new Headers({
|
||||
"Content-Type": "application/octet-stream",
|
||||
});
|
||||
return Promise.resolve({
|
||||
body,
|
||||
init: { status: 200, headers },
|
||||
});
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS.
|
||||
function dataVarResponse(request: any) {
|
||||
const url = new URL(request.url);
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS.
|
||||
const params = Array.from((url.searchParams as any).entries());
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS.
|
||||
const colNames = params.map((v) => `${(v as any)[0]}/${(v as any)[1]}`);
|
||||
const colSchemas = colNames.map(() => schema.schema.dataframe);
|
||||
const body = getEncodedDataframe(
|
||||
colNames,
|
||||
schema.schema.dataframe.nObs,
|
||||
colSchemas
|
||||
);
|
||||
|
||||
const headers = new Headers({
|
||||
"Content-Type": "application/octet-stream",
|
||||
});
|
||||
return Promise.resolve({
|
||||
body,
|
||||
init: { status: 200, headers },
|
||||
});
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any -- - FIXME: disabled temporarily on migrate to TS.
|
||||
export function responder(request: any) {
|
||||
const url = new URL(request.url);
|
||||
const { pathname } = url;
|
||||
if (pathname.endsWith("/annotations/obs")) {
|
||||
return annotationObsResponse(request);
|
||||
}
|
||||
if (pathname.endsWith("/annotations/var")) {
|
||||
return annotationVarResponse(request);
|
||||
}
|
||||
if (pathname.endsWith("/layout/obs")) {
|
||||
return layoutObsResponse(request);
|
||||
}
|
||||
if (pathname.endsWith("/data/var")) {
|
||||
return dataVarResponse(request);
|
||||
}
|
||||
return Promise.reject(new Error("bad URL"));
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any -- - FIXME: disabled temporarily on migrate to TS.
|
||||
export function withExpected(expectedURL: any, expectedParams: any) {
|
||||
/*
|
||||
Do some additional error checking
|
||||
*/
|
||||
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any -- - FIXME: disabled temporarily on migrate to TS.
|
||||
return (request: any) => {
|
||||
// if URL is bogus, reject the promise
|
||||
const url = new URL(request.url);
|
||||
if (!url.pathname.endsWith(expectedURL)) {
|
||||
return Promise.reject(new Error("Unexpected URL!"));
|
||||
}
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS.
|
||||
const params = Array.from((url.searchParams as any).entries()).sort(
|
||||
// @ts-expect-error ts-migrate(2345) FIXME: Argument of type '(a: unknown, b: unknown) => bool... Remove this comment to see the full error message
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS.
|
||||
(a, b) => (a as any)[0] < (b as any)[0]
|
||||
);
|
||||
expectedParams = expectedParams
|
||||
.slice() // eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS.
|
||||
.sort((a: any, b: any) => a[0] < b[0]);
|
||||
|
||||
if (
|
||||
params.length !== expectedParams.length ||
|
||||
!params.every(
|
||||
(p, i) =>
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS.
|
||||
(p as any)[0] === expectedParams[i][0] && // eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS.
|
||||
(p as any)[1] === expectedParams[i][1]
|
||||
)
|
||||
) {
|
||||
return Promise.reject(new Error("unexpected name requested in URL"));
|
||||
}
|
||||
|
||||
return responder(request);
|
||||
};
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any -- - FIXME: disabled temporarily on migrate to TS.
|
||||
export function annotationsObs(names: any) {
|
||||
return withExpected(
|
||||
"/annotations/obs",
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS.
|
||||
names.map((name: any) => ["annotation-name", name])
|
||||
);
|
||||
}
|
||||
+1
-3
@@ -1,6 +1,4 @@
|
||||
import { RawSchema } from "../../../../src/common/types/schema";
|
||||
|
||||
export const schema: { schema: RawSchema } = {
|
||||
export const schema = {
|
||||
schema: {
|
||||
annotations: {
|
||||
obs: {
|
||||
+1691
-5275
File diff suppressed because it is too large
Load Diff
+60
-83
@@ -4,34 +4,13 @@ import {
|
||||
_whereCacheCreate,
|
||||
_whereCacheMerge,
|
||||
} from "../../../src/annoMatrix/whereCache";
|
||||
import { Field, Schema } from "../../../src/common/types/schema";
|
||||
import { Query } from "../../../src/annoMatrix/query";
|
||||
|
||||
const schema = {} as Schema;
|
||||
const schema = {};
|
||||
|
||||
describe("whereCache", () => {
|
||||
test("whereCacheGet - where query, missing cache values", () => {
|
||||
expect(
|
||||
_whereCacheGet({}, schema, Field.X, {
|
||||
where: {
|
||||
field: Field.var,
|
||||
column: "foo",
|
||||
value: "bar",
|
||||
},
|
||||
})
|
||||
).toEqual([undefined]);
|
||||
expect(
|
||||
_whereCacheGet({}, schema, Field.X, {
|
||||
summarize: {
|
||||
method: "mean",
|
||||
field: Field.var,
|
||||
column: "foo",
|
||||
values: ["bar"],
|
||||
},
|
||||
})
|
||||
).toEqual([undefined]);
|
||||
expect(
|
||||
_whereCacheGet({ where: { X: {} } }, schema, Field.X, {
|
||||
_whereCacheGet({}, schema, "X", {
|
||||
where: {
|
||||
field: "var",
|
||||
column: "foo",
|
||||
@@ -40,7 +19,25 @@ describe("whereCache", () => {
|
||||
})
|
||||
).toEqual([undefined]);
|
||||
expect(
|
||||
_whereCacheGet({ where: { X: { var: new Map() } } }, schema, Field.X, {
|
||||
_whereCacheGet({}, schema, "X", {
|
||||
summarize: {
|
||||
field: "var",
|
||||
column: "foo",
|
||||
values: ["bar"],
|
||||
},
|
||||
})
|
||||
).toEqual([undefined]);
|
||||
expect(
|
||||
_whereCacheGet({ where: { X: {} } }, schema, "X", {
|
||||
where: {
|
||||
field: "var",
|
||||
column: "foo",
|
||||
value: "bar",
|
||||
},
|
||||
})
|
||||
).toEqual([undefined]);
|
||||
expect(
|
||||
_whereCacheGet({ where: { X: { var: new Map() } } }, schema, "X", {
|
||||
where: {
|
||||
field: "var",
|
||||
column: "foo",
|
||||
@@ -52,7 +49,7 @@ describe("whereCache", () => {
|
||||
_whereCacheGet(
|
||||
{ where: { X: { var: new Map([["foo", new Map()]]) } } },
|
||||
schema,
|
||||
Field.X,
|
||||
"X",
|
||||
{
|
||||
where: {
|
||||
field: "var",
|
||||
@@ -66,7 +63,7 @@ describe("whereCache", () => {
|
||||
|
||||
test("whereCacheGet - summarize query, missing cache values", () => {
|
||||
expect(
|
||||
_whereCacheGet({}, schema, Field.X, {
|
||||
_whereCacheGet({}, schema, "X", {
|
||||
summarize: {
|
||||
method: "mean",
|
||||
field: "var",
|
||||
@@ -79,7 +76,7 @@ describe("whereCache", () => {
|
||||
_whereCacheGet(
|
||||
{ summarize: { X: { mean: { var: new Map() } } } },
|
||||
schema,
|
||||
Field.X,
|
||||
"X",
|
||||
{
|
||||
summarize: {
|
||||
method: "mean",
|
||||
@@ -125,7 +122,7 @@ describe("whereCache", () => {
|
||||
};
|
||||
|
||||
expect(
|
||||
_whereCacheGet(whereCache, schema, Field.X, {
|
||||
_whereCacheGet(whereCache, schema, "X", {
|
||||
where: {
|
||||
field: "var",
|
||||
column: "foo",
|
||||
@@ -134,7 +131,7 @@ describe("whereCache", () => {
|
||||
})
|
||||
).toEqual([0]);
|
||||
expect(
|
||||
_whereCacheGet(whereCache, schema, Field.X, {
|
||||
_whereCacheGet(whereCache, schema, "X", {
|
||||
summarize: {
|
||||
method: "mean",
|
||||
field: "var",
|
||||
@@ -144,7 +141,7 @@ describe("whereCache", () => {
|
||||
})
|
||||
).toEqual([0]);
|
||||
expect(
|
||||
_whereCacheGet(whereCache, schema, Field.X, {
|
||||
_whereCacheGet(whereCache, schema, "X", {
|
||||
where: {
|
||||
field: "var",
|
||||
column: "foo",
|
||||
@@ -153,7 +150,7 @@ describe("whereCache", () => {
|
||||
})
|
||||
).toEqual([1, 2]);
|
||||
expect(
|
||||
_whereCacheGet(whereCache, schema, Field.X, {
|
||||
_whereCacheGet(whereCache, schema, "X", {
|
||||
summarize: {
|
||||
method: "mean",
|
||||
field: "var",
|
||||
@@ -162,12 +159,9 @@ describe("whereCache", () => {
|
||||
},
|
||||
})
|
||||
).toEqual([1, 2]);
|
||||
expect(_whereCacheGet(whereCache, schema, "Y", {})).toEqual([undefined]);
|
||||
expect(
|
||||
// Force invalid field value Y
|
||||
_whereCacheGet(whereCache, schema, "Y" as Field, {} as Query)
|
||||
).toEqual([undefined]);
|
||||
expect(
|
||||
_whereCacheGet(whereCache, schema, Field.X, {
|
||||
_whereCacheGet(whereCache, schema, "X", {
|
||||
where: {
|
||||
field: "whoknows",
|
||||
column: "whatever",
|
||||
@@ -176,7 +170,7 @@ describe("whereCache", () => {
|
||||
})
|
||||
).toEqual([undefined]);
|
||||
expect(
|
||||
_whereCacheGet(whereCache, schema, Field.X, {
|
||||
_whereCacheGet(whereCache, schema, "X", {
|
||||
where: {
|
||||
field: "var",
|
||||
column: "whatever",
|
||||
@@ -185,7 +179,7 @@ describe("whereCache", () => {
|
||||
})
|
||||
).toEqual([undefined]);
|
||||
expect(
|
||||
_whereCacheGet(whereCache, schema, Field.X, {
|
||||
_whereCacheGet(whereCache, schema, "X", {
|
||||
where: {
|
||||
field: "var",
|
||||
column: "foo",
|
||||
@@ -204,7 +198,7 @@ describe("whereCache", () => {
|
||||
},
|
||||
};
|
||||
const wc = _whereCacheCreate(
|
||||
Field.obs,
|
||||
"field",
|
||||
{
|
||||
where: {
|
||||
field: "queryField",
|
||||
@@ -218,27 +212,18 @@ describe("whereCache", () => {
|
||||
expect(wc).toEqual(
|
||||
expect.objectContaining({
|
||||
where: {
|
||||
[Field.obs]: {
|
||||
field: {
|
||||
queryField: expect.any(Map),
|
||||
},
|
||||
},
|
||||
})
|
||||
);
|
||||
// @ts-expect-error ts-migrate(2531) FIXME: Object is possibly 'null'.
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS.
|
||||
expect((wc.where as any)[Field.obs].queryField.has("queryColumn")).toEqual(true);
|
||||
expect(wc.where.field.queryField.has("queryColumn")).toEqual(true);
|
||||
expect(wc.where.field.queryField.get("queryColumn")).toBeInstanceOf(Map);
|
||||
expect(
|
||||
// @ts-expect-error ts-migrate(2531) FIXME: Object is possibly 'null'.
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS.
|
||||
(wc.where as any)[Field.obs].queryField.get("queryColumn")
|
||||
).toBeInstanceOf(Map);
|
||||
expect(
|
||||
// @ts-expect-error ts-migrate(2531) FIXME: Object is possibly 'null'.
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS.
|
||||
(wc.where as any)[Field.obs].queryField.get("queryColumn").has("queryValue")
|
||||
wc.where.field.queryField.get("queryColumn").has("queryValue")
|
||||
).toEqual(true);
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion --- assert wc to be non-null
|
||||
expect(_whereCacheGet(wc!, schema, Field.obs, query)).toEqual([0, 1, 2]);
|
||||
expect(_whereCacheGet(wc, schema, "field", query)).toEqual([0, 1, 2]);
|
||||
});
|
||||
|
||||
test("whereCacheCreate, summarize query", () => {
|
||||
@@ -250,14 +235,12 @@ describe("whereCache", () => {
|
||||
values: ["queryValue"],
|
||||
},
|
||||
};
|
||||
const wc = _whereCacheCreate(Field.obs, query, [0, 1, 2]);
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion --- assert wc to be non-null
|
||||
expect(_whereCacheGet(wc!, schema, Field.obs, query)).toEqual([0, 1, 2]);
|
||||
const wc = _whereCacheCreate("field", query, [0, 1, 2]);
|
||||
expect(_whereCacheGet(wc, schema, "field", query)).toEqual([0, 1, 2]);
|
||||
});
|
||||
|
||||
test("whereCacheCreate, unknown query type", () => {
|
||||
// @ts-expect-error --- force invalid query {foobar: true}
|
||||
expect(_whereCacheCreate(Field.obs, { foobar: true }, [1])).toEqual({});
|
||||
expect(_whereCacheCreate("field", { foobar: true }, [1])).toEqual({});
|
||||
});
|
||||
|
||||
test("whereCacheMerge, where queries", () => {
|
||||
@@ -265,20 +248,19 @@ describe("whereCache", () => {
|
||||
|
||||
// remember, will mutate dst
|
||||
const src = _whereCacheCreate(
|
||||
Field.obs,
|
||||
"field",
|
||||
{ where: { field: "queryField", column: "queryColumn", value: "foo" } },
|
||||
["foo"]
|
||||
);
|
||||
|
||||
const dst1 = _whereCacheCreate(
|
||||
Field.obs,
|
||||
"field",
|
||||
{ where: { field: "queryField", column: "queryColumn", value: "bar" } },
|
||||
["dst1"]
|
||||
);
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion --- assert dst1 and src to be non-null
|
||||
wc = _whereCacheMerge(dst1!, src!);
|
||||
wc = _whereCacheMerge(dst1, src);
|
||||
expect(
|
||||
_whereCacheGet(wc, schema, Field.obs, {
|
||||
_whereCacheGet(wc, schema, "field", {
|
||||
where: {
|
||||
field: "queryField",
|
||||
column: "queryColumn",
|
||||
@@ -287,7 +269,7 @@ describe("whereCache", () => {
|
||||
})
|
||||
).toEqual(["foo"]);
|
||||
expect(
|
||||
_whereCacheGet(wc, schema, Field.obs, {
|
||||
_whereCacheGet(wc, schema, "field", {
|
||||
where: {
|
||||
field: "queryField",
|
||||
column: "queryColumn",
|
||||
@@ -297,14 +279,13 @@ describe("whereCache", () => {
|
||||
).toEqual(["dst1"]);
|
||||
|
||||
const dst2 = _whereCacheCreate(
|
||||
Field.obs,
|
||||
"field",
|
||||
{ where: { field: "queryField", column: "queryColumn", value: "bar" } },
|
||||
["dst2"]
|
||||
);
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion --- assert dst2m, dst1 and src to be non-null
|
||||
wc = _whereCacheMerge(dst2!, dst1!, src!);
|
||||
wc = _whereCacheMerge(dst2, dst1, src);
|
||||
expect(
|
||||
_whereCacheGet(wc, schema, Field.obs, {
|
||||
_whereCacheGet(wc, schema, "field", {
|
||||
where: {
|
||||
field: "queryField",
|
||||
column: "queryColumn",
|
||||
@@ -313,7 +294,7 @@ describe("whereCache", () => {
|
||||
})
|
||||
).toEqual(["foo"]);
|
||||
expect(
|
||||
_whereCacheGet(wc, schema, Field.obs, {
|
||||
_whereCacheGet(wc, schema, "field", {
|
||||
where: {
|
||||
field: "queryField",
|
||||
column: "queryColumn",
|
||||
@@ -322,20 +303,17 @@ describe("whereCache", () => {
|
||||
})
|
||||
).toEqual(["dst1"]);
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion --- assert src to be non-null
|
||||
wc = _whereCacheMerge({}, src!);
|
||||
wc = _whereCacheMerge({}, src);
|
||||
expect(wc).toEqual(src);
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion --- assert src to be non-null
|
||||
wc = _whereCacheMerge({ where: { obs: { queryField: new Map() } } }, src!);
|
||||
wc = _whereCacheMerge({ where: { field: { queryField: new Map() } } }, src);
|
||||
expect(wc).toEqual(src);
|
||||
});
|
||||
|
||||
test("whereCacheMerge, mixed queries", () => {
|
||||
const wc = _whereCacheMerge(
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion --- assert wc to be non-null
|
||||
_whereCacheCreate(
|
||||
Field.obs,
|
||||
"field",
|
||||
{
|
||||
where: {
|
||||
field: "queryField",
|
||||
@@ -344,10 +322,9 @@ describe("whereCache", () => {
|
||||
},
|
||||
},
|
||||
["a"]
|
||||
)!,
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion --- assert wc to be non-null
|
||||
),
|
||||
_whereCacheCreate(
|
||||
Field.obs,
|
||||
"field",
|
||||
{
|
||||
summarize: {
|
||||
method: "mean",
|
||||
@@ -357,11 +334,11 @@ describe("whereCache", () => {
|
||||
},
|
||||
},
|
||||
["b"]
|
||||
)!
|
||||
)
|
||||
);
|
||||
|
||||
expect(
|
||||
_whereCacheGet(wc, schema, Field.obs, {
|
||||
_whereCacheGet(wc, schema, "field", {
|
||||
where: {
|
||||
field: "queryField",
|
||||
column: "queryColumn",
|
||||
@@ -371,7 +348,7 @@ describe("whereCache", () => {
|
||||
).toEqual(["a"]);
|
||||
|
||||
expect(
|
||||
_whereCacheGet(wc, schema, Field.obs, {
|
||||
_whereCacheGet(wc, schema, "field", {
|
||||
summarize: {
|
||||
method: "mean",
|
||||
field: "queryField",
|
||||
@@ -382,7 +359,7 @@ describe("whereCache", () => {
|
||||
).toEqual(["b"]);
|
||||
|
||||
expect(
|
||||
_whereCacheGet(wc, schema, Field.obs, {
|
||||
_whereCacheGet(wc, schema, "field", {
|
||||
where: {
|
||||
field: "queryField",
|
||||
column: "queryColumn",
|
||||
@@ -392,7 +369,7 @@ describe("whereCache", () => {
|
||||
).toEqual([undefined]);
|
||||
|
||||
expect(
|
||||
_whereCacheGet(wc, schema, Field.obs, {
|
||||
_whereCacheGet(wc, schema, "field", {
|
||||
summarize: {
|
||||
method: "no-such-method",
|
||||
field: "queryField",
|
||||
Reference in New Issue
Block a user