UNPKG

jinaga

Version:

Data management for web and mobile applications.

90 lines (74 loc) 3.22 kB
import { FactEnvelope, FactReference, PredecessorCollection } from "../storage"; export type IndexPredecessorCollection = { [role: string]: number | number[]; }; export class GraphSerializer { private index = 0; private indexByFactReference: { [key: string]: number } = {}; private publicKeys: string[] = []; constructor( private readonly write: (chunk: string) => void ) {} serialize(result: FactEnvelope[]) { // Write the facts for (const fact of result) { // Skip facts that have already been written const key = fact.fact.type + ":" + fact.fact.hash; if (this.indexByFactReference.hasOwnProperty(key)) { continue; } // Write any new public keys for (const signature of fact.signatures) { if (!this.publicKeys.includes(signature.publicKey)) { const pkIndex = this.publicKeys.length; const publicKey = JSON.stringify(signature.publicKey); this.write(`PK${pkIndex.toString()}\n${publicKey}\n\n`); this.publicKeys.push(signature.publicKey); } } // Write the fact const factType = JSON.stringify(fact.fact.type); const predecessorIndexes = JSON.stringify(this.getPredecessorIndexes(fact.fact.predecessors)); const factFields = JSON.stringify(fact.fact.fields); let output = `${factType}\n${predecessorIndexes}\n${factFields}`; // Write the signatures for (const signature of fact.signatures) { const publicKeyIndex = this.publicKeys.indexOf(signature.publicKey); const publicKey = `PK${publicKeyIndex.toString()}`; const signatureString = JSON.stringify(signature.signature); output += `\n${publicKey}\n${signatureString}`; } output += "\n\n"; this.write(output); this.indexByFactReference[key] = this.index; this.index++; } } private getPredecessorIndexes(predecessors: PredecessorCollection): IndexPredecessorCollection { const result: IndexPredecessorCollection = {}; for (const role in predecessors) { const reference = predecessors[role]; if (Array.isArray(reference)) { result[role] = reference.map(r => this.getFactIndex(r)); } else { result[role] = this.getFactIndex(reference); } } return result; } private getFactIndex(reference: FactReference): number { const key = reference.type + ":" + reference.hash; if (!this.indexByFactReference.hasOwnProperty(key)) { throw new Error(`Fact reference not found in graph: ${key}`); } return this.indexByFactReference[key]; } } export function serializeGraph(graph: FactEnvelope[]) { const serializedData: string[] = []; const serializer = new GraphSerializer(chunk => serializedData.push(chunk)); serializer.serialize(graph); const body = serializedData.join(''); return body; }