Add RelationalView.{to,from}JSON (#443)
This adds methods for serializing the GitHub RelationalView. We have not put in the work to ensure that these methods generate canonical data. Getting the issues in a different order, or finding references in a different order, can change the JSON output even if the resulting repositories are equivalent. @decentralion think it's not worth putting in the effort, since we may switch to a SQL database soon anyway. Test plan: travis Paired with @wchargin
This commit is contained in:
parent
64df5b09c3
commit
6356c5477f
|
@ -1,5 +1,6 @@
|
||||||
// @flow
|
// @flow
|
||||||
|
|
||||||
|
import {toCompat, fromCompat, type Compatible} from "../../util/compat";
|
||||||
import stringify from "json-stable-stringify";
|
import stringify from "json-stable-stringify";
|
||||||
import {parseReferences} from "./parseReferences";
|
import {parseReferences} from "./parseReferences";
|
||||||
import * as N from "./nodes";
|
import * as N from "./nodes";
|
||||||
|
@ -22,6 +23,11 @@ import {
|
||||||
reviewCommentUrlToId,
|
reviewCommentUrlToId,
|
||||||
} from "./urlIdParse";
|
} from "./urlIdParse";
|
||||||
|
|
||||||
|
const COMPAT_INFO = {
|
||||||
|
type: "sourcecred/github/relationalView",
|
||||||
|
version: "0.1.0",
|
||||||
|
};
|
||||||
|
|
||||||
export class RelationalView {
|
export class RelationalView {
|
||||||
_repos: Map<N.RawAddress, RepoEntry>;
|
_repos: Map<N.RawAddress, RepoEntry>;
|
||||||
_issues: Map<N.RawAddress, IssueEntry>;
|
_issues: Map<N.RawAddress, IssueEntry>;
|
||||||
|
@ -164,6 +170,34 @@ export class RelationalView {
|
||||||
yield* this.userlikes();
|
yield* this.userlikes();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
toJSON(): RelationalViewJSON {
|
||||||
|
const rawJSON = {
|
||||||
|
repos: addressMapToObject(this._repos),
|
||||||
|
issues: addressMapToObject(this._issues),
|
||||||
|
pulls: addressMapToObject(this._pulls),
|
||||||
|
reviews: addressMapToObject(this._reviews),
|
||||||
|
comments: addressMapToObject(this._comments),
|
||||||
|
userlikes: addressMapToObject(this._userlikes),
|
||||||
|
references: addressMapToObject(this._mapReferences),
|
||||||
|
referencedBy: addressMapToObject(this._mapReferencedBy),
|
||||||
|
};
|
||||||
|
return toCompat(COMPAT_INFO, rawJSON);
|
||||||
|
}
|
||||||
|
|
||||||
|
static fromJSON(compatJson: RelationalViewJSON): RelationalView {
|
||||||
|
const json = fromCompat(COMPAT_INFO, compatJson);
|
||||||
|
const rv = new RelationalView();
|
||||||
|
rv._repos = objectToAddressMap(json.repos);
|
||||||
|
rv._issues = objectToAddressMap(json.issues);
|
||||||
|
rv._pulls = objectToAddressMap(json.pulls);
|
||||||
|
rv._reviews = objectToAddressMap(json.reviews);
|
||||||
|
rv._comments = objectToAddressMap(json.comments);
|
||||||
|
rv._userlikes = objectToAddressMap(json.userlikes);
|
||||||
|
rv._mapReferences = objectToAddressMap(json.references);
|
||||||
|
rv._mapReferencedBy = objectToAddressMap(json.referencedBy);
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
_addRepo(json: Q.RepositoryJSON) {
|
_addRepo(json: Q.RepositoryJSON) {
|
||||||
const address: RepoAddress = {
|
const address: RepoAddress = {
|
||||||
type: N.REPO_TYPE,
|
type: N.REPO_TYPE,
|
||||||
|
@ -736,3 +770,36 @@ export type TextContentEntity = Issue | Pull | Review | Comment;
|
||||||
export type ParentEntity = Repo | Issue | Pull | Review;
|
export type ParentEntity = Repo | Issue | Pull | Review;
|
||||||
export type ChildEntity = Issue | Pull | Review | Comment;
|
export type ChildEntity = Issue | Pull | Review | Comment;
|
||||||
export type ReferentEntity = Repo | Issue | Pull | Review | Comment | Userlike;
|
export type ReferentEntity = Repo | Issue | Pull | Review | Comment | Userlike;
|
||||||
|
|
||||||
|
function addressMapToObject<T>(
|
||||||
|
x: Map<N.RawAddress, T>
|
||||||
|
): AddressEntryMapJSON<T> {
|
||||||
|
const result: {[N.RawAddress]: T} = {};
|
||||||
|
for (const [address, entry] of x.entries()) {
|
||||||
|
result[address] = entry;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
function objectToAddressMap<T>(
|
||||||
|
x: AddressEntryMapJSON<T>
|
||||||
|
): Map<N.RawAddress, T> {
|
||||||
|
const result = new Map();
|
||||||
|
for (const key of Object.keys(x)) {
|
||||||
|
const address: N.RawAddress = (key: any);
|
||||||
|
result.set(address, x[address]);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
export opaque type AddressEntryMapJSON<T> = {[N.RawAddress]: T};
|
||||||
|
export opaque type RelationalViewJSON = Compatible<{|
|
||||||
|
+repos: AddressEntryMapJSON<RepoEntry>,
|
||||||
|
+issues: AddressEntryMapJSON<IssueEntry>,
|
||||||
|
+pulls: AddressEntryMapJSON<PullEntry>,
|
||||||
|
+reviews: AddressEntryMapJSON<ReviewEntry>,
|
||||||
|
+comments: AddressEntryMapJSON<CommentEntry>,
|
||||||
|
+userlikes: AddressEntryMapJSON<UserlikeEntry>,
|
||||||
|
+references: AddressEntryMapJSON<N.ReferentAddress[]>,
|
||||||
|
+referencedBy: AddressEntryMapJSON<N.TextContentAddress[]>,
|
||||||
|
|}>;
|
||||||
|
|
|
@ -223,4 +223,13 @@ describe("plugins/github/relationalView", () => {
|
||||||
// may be fragile
|
// may be fragile
|
||||||
expect(rv1).toEqual(rv2);
|
expect(rv1).toEqual(rv2);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe("to/fromJSON", () => {
|
||||||
|
it("to->from->to is identity", () => {
|
||||||
|
const json1 = view.toJSON();
|
||||||
|
const view1 = R.RelationalView.fromJSON(json1);
|
||||||
|
const json2 = view1.toJSON();
|
||||||
|
expect(json1).toEqual(json2);
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in New Issue