import * as mongodb from 'mongodb'; import { Transferable } from './Message'; export class Database { public static DocumentsCollection = 'documents'; public static Instance = new Database(); private MongoClient = mongodb.MongoClient; private url = 'mongodb://localhost:27017/Dash'; private currentWrites: { [id: string]: Promise } = {}; private db?: mongodb.Db; private onConnect: (() => void)[] = []; constructor() { this.MongoClient.connect(this.url, (err, client) => { this.db = client.db(); this.onConnect.forEach(fn => fn()); }); } public update(id: string, value: any, callback: () => void, upsert = true, collectionName = Database.DocumentsCollection) { if (this.db) { let collection = this.db.collection(collectionName); const prom = this.currentWrites[id]; let newProm: Promise; const run = (): Promise => { return new Promise(resolve => { collection.updateOne({ _id: id }, value, { upsert } , (err, res) => { if (this.currentWrites[id] === newProm) { delete this.currentWrites[id]; } resolve(); callback(); }); }); }; newProm = prom ? prom.then(run) : run(); this.currentWrites[id] = newProm; } else { this.onConnect.push(() => this.update(id, value, callback, upsert, collectionName)); } } public delete(query: any, collectionName?: string): Promise; public delete(id: string, collectionName?: string): Promise; public delete(id: any, collectionName = Database.DocumentsCollection) { if (typeof id === "string") { id = { _id: id }; } if (this.db) { const db = this.db; return new Promise(res => db.collection(collectionName).deleteMany(id, (err, result) => res(result))); } else { return new Promise(res => this.onConnect.push(() => res(this.delete(id, collectionName)))); } } public deleteAll(collectionName = Database.DocumentsCollection): Promise { return new Promise(res => { if (this.db) { this.db.collection(collectionName).deleteMany({}, res); } else { this.onConnect.push(() => this.db && this.db.collection(collectionName).deleteMany({}, res)); } }); } public insert(value: any, collectionName = Database.DocumentsCollection) { if (this.db) { if ("id" in value) { value._id = value.id; delete value.id; } const id = value._id; const collection = this.db.collection(collectionName); const prom = this.currentWrites[id]; let newProm: Promise; const run = (): Promise => { return new Promise(resolve => { collection.insertOne(value, (err, res) => { if (this.currentWrites[id] === newProm) { delete this.currentWrites[id]; } resolve(); }); }); }; newProm = prom ? prom.then(run) : run(); this.currentWrites[id] = newProm; } else { this.onConnect.push(() => this.insert(value, collectionName)); } } public getDocument(id: string, fn: (result?: Transferable) => void, collectionName = Database.DocumentsCollection) { if (this.db) { this.db.collection(collectionName).findOne({ _id: id }, (err, result) => { if (result) { result.id = result._id; delete result._id; fn(result); } else { fn(undefined); } }); } else { this.onConnect.push(() => this.getDocument(id, fn, collectionName)); } } public getDocuments(ids: string[], fn: (result: Transferable[]) => void, collectionName = Database.DocumentsCollection) { if (this.db) { this.db.collection(collectionName).find({ _id: { "$in": ids } }).toArray((err, docs) => { if (err) { console.log(err.message); console.log(err.errmsg); } fn(docs.map(doc => { doc.id = doc._id; delete doc._id; return doc; })); }); } else { this.onConnect.push(() => this.getDocuments(ids, fn, collectionName)); } } public query(query: any, collectionName = "newDocuments"): Promise { if (this.db) { return Promise.resolve(this.db.collection(collectionName).find(query)); } else { return new Promise(res => { this.onConnect.push(() => res(this.query(query, collectionName))); }); } } public print() { console.log("db says hi!"); } }