|
|
@@ -60,10 +60,11 @@ export class Database {
|
|
|
`CREATE TABLE ServerDataValue (
|
|
|
ID INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
|
EntryID INTEGER NOT NULL,
|
|
|
+ Type Text NOT NULL,
|
|
|
Key TEXT NOT NULL,
|
|
|
Value REAL NOT NULL,
|
|
|
FOREIGN KEY(EntryID) REFERENCES ServerDataEntry(ID),
|
|
|
- UNIQUE(EntryID, Key)
|
|
|
+ UNIQUE(EntryID, Type, Key)
|
|
|
);`,
|
|
|
[]
|
|
|
);
|
|
|
@@ -110,6 +111,68 @@ export class Database {
|
|
|
}, [] as Server[]);
|
|
|
}
|
|
|
|
|
|
+ public async insertServerData(serverID: number, data: ReducedData[]) {
|
|
|
+ if (!data.length) return;
|
|
|
+
|
|
|
+ await this.beginTransaction();
|
|
|
+ try {
|
|
|
+ let c = 1;
|
|
|
+ for (const entry of data) {
|
|
|
+ const result = await this.run('INSERT INTO ServerDataEntry(ServerID, Timestamp) VALUES(?, ?);', [serverID, entry.time.getTime()]);
|
|
|
+ let entryID = result.lastID;
|
|
|
+
|
|
|
+ for (const type of Object.keys(entry).filter(t => t !== 'time')) {
|
|
|
+ for (const key of Object.keys(entry[type])) {
|
|
|
+ await this.run('INSERT INTO ServerDataValue(EntryID, Type, Key, Value) VALUES(?, ?, ?, ?);', [entryID, type, key, entry[type][key]]);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ c++;
|
|
|
+ }
|
|
|
+ await this.commit();
|
|
|
+ } catch (err) {
|
|
|
+ await this.rollback();
|
|
|
+ throw err;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public async getServerData(serverID: number, start: Date, end: Date): Promise<ReducedData[]> {
|
|
|
+ /* FIRST DRAFT - SIMPLY GET ALL DATA POINTS OF ALL TYPES */
|
|
|
+ /* TODO: ONLY GET DATA OF ONE TYPE, REDUCE DOWN TO FEWER DATA POINTS, COMPUTING AVGs & PEAKs */
|
|
|
+
|
|
|
+ const result = await this.stmt(
|
|
|
+ `SELECT
|
|
|
+ ServerDataEntry.*,
|
|
|
+ ServerDataValue.Type,
|
|
|
+ ServerDataValue.Key,
|
|
|
+ ServerDataValue.Value
|
|
|
+ FROM ServerDataEntry
|
|
|
+ JOIN ServerDataValue ON ServerDataEntry.ID = ServerDataValue.EntryID
|
|
|
+ WHERE ServerID = ?
|
|
|
+ AND Timestamp BETWEEN ? AND ?
|
|
|
+ ORDER BY Timestamp, Type, Key;`,
|
|
|
+ [serverID, start.getTime(), end.getTime()]
|
|
|
+ );
|
|
|
+
|
|
|
+ return result.rows.reduce((res, line, i) => {
|
|
|
+ const timestamp = line['Timestamp'];
|
|
|
+ let entry: ReducedData;
|
|
|
+ if (i === 0 || res[res.length - 1].time.getTime() !== timestamp) {
|
|
|
+ entry = { time: new Date(timestamp) } as ReducedData;
|
|
|
+ res.push(entry);
|
|
|
+ } else {
|
|
|
+ entry = res[res.length - 1];
|
|
|
+ }
|
|
|
+
|
|
|
+ const type = line['Type'];
|
|
|
+ if (typeof entry[type] === 'undefined') {
|
|
|
+ entry[type] = {};
|
|
|
+ }
|
|
|
+ entry[type][line['Key']] = line['Value'];
|
|
|
+
|
|
|
+ return res;
|
|
|
+ }, [] as ReducedData[]);
|
|
|
+ }
|
|
|
+
|
|
|
private async run(sql: string, params: any): Promise<RunResult> {
|
|
|
return new Promise<RunResult>((res, rej) => {
|
|
|
this.db.run(sql, params, function (err) {
|
|
|
@@ -128,4 +191,16 @@ export class Database {
|
|
|
});
|
|
|
});
|
|
|
}
|
|
|
+
|
|
|
+ public async beginTransaction() {
|
|
|
+ await this.run('BEGIN TRANSACTION;', []);
|
|
|
+ }
|
|
|
+
|
|
|
+ public async commit() {
|
|
|
+ await this.run('COMMIT;', []);
|
|
|
+ }
|
|
|
+
|
|
|
+ public async rollback() {
|
|
|
+ await this.run('ROLLBACK;', []);
|
|
|
+ }
|
|
|
}
|