UNPKG

lakutata

Version:

An IoC-based universal application framework.

328 lines (321 loc) 9.57 kB
import t from "events"; import { Buffer as e } from "buffer"; import { MongoClient as n, GridFSBucket as s, MongoServerError as a } from "mongodb"; var o = new Set([ "url", "collection", "namespace", "serialize", "deserialize", "uri", "useGridFS", "dialect", "db" ]); var i = class extends t { ttlSupport=false; opts; connect; namespace; constructor(t, e) { super(); t ??= {}; if (typeof t === "string") { t = { url: t }; } if (t.uri) { t = { url: t.uri, ...t }; } this.opts = { url: "mongodb://127.0.0.1:27017", collection: "keyv", ...t, ...e }; delete this.opts.emitErrors; const a = Object.fromEntries(Object.entries(this.opts).filter((([t]) => !o.has(t)))); this.opts = Object.fromEntries(Object.entries(this.opts).filter((([t]) => o.has(t)))); this.connect = new Promise((async (t, e) => { try { let e = ""; if (this.opts.url) { e = this.opts.url; } const o = new n(e, a); await o.connect(); const i = o.db(this.opts.db); if (this.opts.useGridFS) { const e = new s(i, { readPreference: this.opts.readPreference, bucketName: this.opts.collection }); const n = i.collection(`${this.opts.collection}.files`); await n.createIndex({ uploadDate: -1 }); await n.createIndex({ "metadata.expiresAt": 1 }); await n.createIndex({ "metadata.lastAccessed": 1 }); await n.createIndex({ "metadata.filename": 1 }); t({ bucket: e, store: n, db: i, mongoClient: o }); } else { let e = "keyv"; if (this.opts.collection) { e = this.opts.collection; } const n = i.collection(e); await n.createIndex({ key: 1 }, { unique: true, background: true }); await n.createIndex({ expiresAt: 1 }, { expireAfterSeconds: 0, background: true }); t({ store: n, mongoClient: o }); } } catch (t) { this.emit("error", t); } })); } async get(t) { const n = await this.connect; if (this.opts.useGridFS) { await n.store.updateOne({ filename: t }, { $set: { "metadata.lastAccessed": new Date } }); const s = n.bucket.openDownloadStreamByName(t); return new Promise((t => { const n = []; s.on("error", (() => { t(void 0); })); s.on("end", (() => { const s = e.concat(n).toString("utf8"); t(s); })); s.on("data", (t => { n.push(t); })); })); } const s = await n.store.findOne({ key: { $eq: t } }); if (!s) { return void 0; } return s.value; } async getMany(t) { if (this.opts.useGridFS) { const e = []; for (const n of t) { e.push(this.get(n)); } const n = await Promise.allSettled(e); const s = []; for (const t of n) { s.push(t.value); } return s; } const e = await this.connect; const n = await e.store.s.db.collection(this.opts.collection).find({ key: { $in: t } }).project({ _id: 0, value: 1, key: 1 }).toArray(); const s = [ ...t ]; let a = 0; for (const e of t) { const t = n.findIndex((t => t.key === e)); s[a] = t > -1 ? n[t].value : void 0; a++; } return s; } async set(t, e, n) { const s = typeof n === "number" ? new Date(Date.now() + n) : null; if (this.opts.useGridFS) { const n = await this.connect; const a = n.bucket.openUploadStream(t, { metadata: { expiresAt: s, lastAccessed: new Date } }); return new Promise((t => { a.on("finish", (() => { t(a); })); a.end(e); })); } const a = await this.connect; await a.store.updateOne({ key: { $eq: t } }, { $set: { key: t, value: e, expiresAt: s } }, { upsert: true }); } async delete(t) { if (typeof t !== "string") { return false; } const e = await this.connect; if (this.opts.useGridFS) { try { const n = e.db; const a = new s(n, { bucketName: this.opts.collection }); const o = await a.find({ filename: t }).toArray(); await e.bucket.delete(o[0]._id); return true; } catch { return false; } } const n = await e.store.deleteOne({ key: { $eq: t } }); return n.deletedCount > 0; } async deleteMany(t) { const e = await this.connect; if (this.opts.useGridFS) { const n = e.db; const a = new s(n, { bucketName: this.opts.collection }); const o = await a.find({ filename: { $in: t } }).toArray(); if (o.length === 0) { return false; } await Promise.all(o.map((async t => e.bucket.delete(t._id)))); return true; } const n = await e.store.deleteMany({ key: { $in: t } }); return n.deletedCount > 0; } async clear() { const t = await this.connect; if (this.opts.useGridFS) { try { await t.bucket.drop(); } catch (t) { if (!(t instanceof a && t.code === 26)) { throw t; } } } await t.store.deleteMany({ key: { $regex: this.namespace ? `^${this.namespace}:*` : "" } }); } async clearExpired() { if (!this.opts.useGridFS) { return false; } return this.connect.then((async t => { const e = t.db; const n = new s(e, { bucketName: this.opts.collection }); return n.find({ "metadata.expiresAt": { $lte: new Date(Date.now()) } }).toArray().then((async e => Promise.all(e.map((async e => t.bucket.delete(e._id)))).then((() => true)))); })); } async clearUnusedFor(t) { if (!this.opts.useGridFS) { return false; } const e = await this.connect; const n = e.db; const a = new s(n, { bucketName: this.opts.collection }); const o = await a.find({ "metadata.lastAccessed": { $lte: new Date(Date.now() - t * 1e3) } }).toArray(); await Promise.all(o.map((async t => e.bucket.delete(t._id)))); return true; } async* iterator(t) { const e = await this.connect; const n = new RegExp(`^${t ? t + ":" : ".*"}`); const s = this.opts.useGridFS ? e.store.find({ filename: n }).map((async t => [ t.filename, await this.get(t.filename) ])) : e.store.find({ key: n }).map((t => [ t.key, t.value ])); yield* s; } async has(t) { const e = await this.connect; const n = { [this.opts.useGridFS ? "filename" : "key"]: { $eq: t } }; const s = await e.store.count(n); return s !== 0; } async disconnect() { const t = await this.connect; await t.mongoClient.close(); } }; var c = i; export { i as KeyvMongo, c as default };