lakutata
Version:
An IoC-based universal application framework.
328 lines (321 loc) • 9.57 kB
JavaScript
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 };