/
memory.js
101 lines (88 loc) · 3.2 KB
/
memory.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
// @flow
import mongoose from 'mongoose';
import Util from '../util';
import type { BlockModel, Storage, TimeStateModel } from './types';
const { ObjectId } = mongoose.Types;
function newID(): string {
return ObjectId().toString();
}
class Memory<S, C> implements Storage<S, C> {
timeStates: { [id: string]: TimeStateModel<S, C> };
constructor() {
this.timeStates = {};
}
async createTimeState(time: number, tag: string): Promise<TimeStateModel<S, C>> {
const ts = {
id: newID(),
tag,
blocks: [],
startTime: time,
endTime: time,
};
this.timeStates[ts.id] = ts;
return ts;
}
async addBlock(timeStateId: string, block: BlockModel<S, C>): Promise<BlockModel<S, C>> {
await this.getTimeState(timeStateId);
const ts = this.timeStates[timeStateId];
const lastBlock = ts.blocks[ts.blocks.length - 1];
if (lastBlock) {
const endTime = Util.getBlockEndTime(lastBlock);
if (endTime !== block.time) {
throw new Error(`Cannot add block because starting time ${block.time} does not match previous block's ending time ${endTime}`);
}
}
const obj = { ...block, id: newID() };
ts.blocks.push(obj);
ts.endTime = Util.getBlockEndTime(obj);
return obj;
}
async getTimeState(timeStateId: string): Promise<TimeStateModel<S, C>> {
if (!(timeStateId in this.timeStates)) {
throw new Error(`TimeState not found with id ${timeStateId}`);
}
const ts = this.timeStates[timeStateId];
const newBlocks = [];
for (let i = 0; i < ts.blocks.length; i++) {
const b = { ...ts.blocks[i] };
delete b.changes;
newBlocks.push(b);
}
return { ...ts, blocks: newBlocks };
}
async getBlock(timeStateId: string, blockId: string): Promise<BlockModel<S, C>> {
await this.getTimeState(timeStateId);
const ts = this.timeStates[timeStateId];
for (let i = 0; i < ts.blocks.length; i++) {
const b = ts.blocks[i];
if (b.id === blockId) return b;
}
throw new Error(`Block not found with id ${blockId} in TimeState ${timeStateId}`);
}
async getTimeStates(tag: string): Promise<Array<TimeStateModel<S, C>>> {
const arr = [];
const ids = Object.keys(this.timeStates);
for (let i = 0; i < ids.length; i++) {
const ts = this.timeStates[ids[i]];
if (ts.tag === tag) {
const clone = { ...ts };
if (clone.blocks.length === 0) {
delete this.timeStates[ids[i]];
} else {
delete clone.blocks;
arr.push(clone);
}
}
}
return arr.sort((a, b) => a.startTime - b.startTime);
}
async getTags(): Promise<Array<string>> {
const tags = [];
Object.keys(this.timeStates).forEach((id) => {
const ts = this.timeStates[id];
if (!tags.includes(ts.tag) && !!ts.tag) tags.push(ts.tag);
});
return tags;
}
}
export default Memory;