Add serialization to TimelineCredScores (#1656)

* Add serialization to TimelineCredScores

Right now the serialization is super trivial, we just attach a compat
header. In the future, we can try encoding the float64 arrays as
bytestrings to save space.

Test plan: Unit tests included; `yarn test` passes.

* Fix up serialization per @Beanow's review
This commit is contained in:
Dandelion Mané 2020-03-01 13:49:44 -08:00 committed by GitHub
parent 6c532b51b6
commit 897033b92b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 82 additions and 1 deletions

View File

@ -5,6 +5,7 @@
*/
import {sum} from "d3-array";
import {toCompat, fromCompat, type Compatible} from "../../util/compat";
import {type Interval} from "../interval";
import {type TimelineDistributions} from "./timelinePagerank";
import {NodeAddress, type NodeAddressT} from "../../core/graph";
@ -81,3 +82,28 @@ export function distributionToCred(
});
return {intervalCredScores, intervals};
}
const COMPAT_INFO = {type: "sourcecred/timelineCredScores", version: "0.1.0"};
export type TimelineCredScoresJSON = Compatible<{|
+intervals: $ReadOnlyArray<Interval>,
// TODO: Serializing floats as strings is space-inefficient. We can likely
// get space savings if we base64 encode a byte representation of the
// floats.
+intervalCredScores: $ReadOnlyArray<$ReadOnlyArray<number>>,
|}>;
export function toJSON(s: TimelineCredScores): TimelineCredScoresJSON {
return toCompat(COMPAT_INFO, {
intervals: s.intervals,
intervalCredScores: s.intervalCredScores.map((x) => Array.from(x)),
});
}
export function fromJSON(j: TimelineCredScoresJSON): TimelineCredScores {
const {intervals, intervalCredScores} = fromCompat(COMPAT_INFO, j);
return {
intervals,
intervalCredScores: intervalCredScores.map((x) => new Float64Array(x)),
};
}

View File

@ -1,7 +1,7 @@
// @flow
import {NodeAddress} from "../graph";
import {distributionToCred} from "./distributionToCred";
import {distributionToCred, toJSON, fromJSON} from "./distributionToCred";
describe("src/core/algorithm/distributionToCred", () => {
const na = (...parts) => NodeAddress.fromParts(parts);
@ -128,4 +128,59 @@ describe("src/core/algorithm/distributionToCred", () => {
});
});
});
describe("to/from JSON", () => {
const exampleCred = () => {
const ds = [
{
interval: {startTimeMs: 0, endTimeMs: 10},
intervalWeight: 2,
distribution: new Float64Array([0.5, 0.5]),
},
{
interval: {startTimeMs: 10, endTimeMs: 20},
intervalWeight: 10,
distribution: new Float64Array([0.9, 0.1]),
},
];
const nodeOrder = [na("foo"), na("bar")];
return distributionToCred(ds, nodeOrder, [na("bar")]);
};
it("satisfies round-trip equality", () => {
const json = toJSON(exampleCred());
const result = fromJSON(json);
expect(result).toEqual(exampleCred());
});
it("snapshots as expected", () => {
expect(toJSON(exampleCred())).toMatchInlineSnapshot(`
Array [
Object {
"type": "sourcecred/timelineCredScores",
"version": "0.1.0",
},
Object {
"intervalCredScores": Array [
Array [
2,
2,
],
Array [
90,
10,
],
],
"intervals": Array [
Object {
"endTimeMs": 10,
"startTimeMs": 0,
},
Object {
"endTimeMs": 20,
"startTimeMs": 10,
},
],
},
]
`);
});
});
});