ueberdb2 5.0.39 → 5.0.41

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -3,2260 +3,10 @@ Object.defineProperties(exports, {
3
3
  __esModule: { value: true },
4
4
  [Symbol.toStringTag]: { value: "Module" }
5
5
  });
6
- //#region \0rolldown/runtime.js
7
- var __create = Object.create;
8
- var __defProp = Object.defineProperty;
9
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
10
- var __getOwnPropNames = Object.getOwnPropertyNames;
11
- var __getProtoOf = Object.getPrototypeOf;
12
- var __hasOwnProp = Object.prototype.hasOwnProperty;
13
- var __copyProps = (to, from, except, desc) => {
14
- if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
15
- key = keys[i];
16
- if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
17
- get: ((k) => from[k]).bind(null, key),
18
- enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
19
- });
20
- }
21
- return to;
22
- };
23
- var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
24
- value: mod,
25
- enumerable: true
26
- }) : target, mod));
27
- //#endregion
28
- let util = require("util");
29
- util = __toESM(util);
30
- let cassandra_driver = require("cassandra-driver");
31
- let http = require("http");
32
- http = __toESM(http);
33
- let nano = require("nano");
34
- nano = __toESM(nano);
35
- let dirty_ts = require("dirty-ts");
36
- dirty_ts = __toESM(dirty_ts);
37
- let node_path = require("node:path");
38
- let simple_git = require("simple-git");
39
- let assert = require("assert");
40
- assert = __toESM(assert);
41
- let buffer = require("buffer");
42
- let crypto = require("crypto");
43
- let _elastic_elasticsearch = require("@elastic/elasticsearch");
44
- let events = require("events");
45
- events = __toESM(events);
46
- let mongodb = require("mongodb");
47
- let async = require("async");
48
- async = __toESM(async);
49
- let mssql = require("mssql");
50
- mssql = __toESM(mssql);
51
- let mysql2 = require("mysql2");
52
- let pg = require("pg");
53
- pg = __toESM(pg);
54
- let redis = require("redis");
55
- let rethinkdb = require("rethinkdb");
56
- rethinkdb = __toESM(rethinkdb);
57
- let rusty_store_kv = require("rusty-store-kv");
58
- let surrealdb = require("surrealdb");
59
- //#region lib/CacheAndBufferLayer.ts
60
- /**
61
- * 2011 Peter 'Pita' Martischka
62
- *
63
- * Licensed under the Apache License, Version 2.0 (the "License");
64
- * you may not use this file except in compliance with the License.
65
- * You may obtain a copy of the License at
66
- *
67
- * http://www.apache.org/licenses/LICENSE-2.0
68
- *
69
- * Unless required by applicable law or agreed to in writing, software
70
- * distributed under the License is distributed on an "AS-IS" BASIS,
71
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
72
- * See the License for the specific language governing permissions and
73
- * limitations under the License.
74
- */
75
- /**
76
- * This module is made for the case, you want to use a SQL-Based Databse or a KeyValue Database that
77
- * can only save strings(and no objects), as a JSON KeyValue Store.
78
- *
79
- * The idea of the dbWrapper is to provide following features:
80
- *
81
- * * automatic JSON serialize/deserialize to abstract that away from the database driver and the
82
- * module user.
83
- * * cache reads. A amount of KeyValues are hold in the memory, so that reading is faster.
84
- * * Buffer DB Writings. Sets and deletes should be buffered to make them in a setted interval
85
- * with a bulk. This reduces the overhead of database transactions and makes the database
86
- * faster. But there is also a danger to loose data integrity, to keep that, we should provide a
87
- * flush function.
88
- *
89
- * All Features can be disabled or configured. The Wrapper provides default settings that can be
90
- * overwriden by the driver and by the module user.
91
- */
92
- /**
93
- * Cache with Least Recently Used eviction policy.
94
- */
95
- var LRU = class {
96
- /**
97
- * @param evictable Optional predicate that dictates whether it is permissable to evict the entry
98
- * if it is old and the cache is over capacity. The predicate is passed two arguments (key,
99
- * value). If no predicate is provided, all entries are evictable. Warning: Non-evictable
100
- * entries can cause the cache to go over capacity. If the number of non-evictable entries is
101
- * greater than or equal to the capacity, all new evictable entries will be evicted
102
- * immediately.
103
- */
104
- constructor(capacity, evictable = (k, v) => true) {
105
- this._capacity = capacity;
106
- this._evictable = evictable;
107
- this._cache = /* @__PURE__ */ new Map();
108
- }
109
- /**
110
- * The entries accessed via this iterator are not considered to have been "used" (for purposes of
111
- * determining least recently used).
112
- */
113
- [Symbol.iterator]() {
114
- return this._cache.entries();
115
- }
116
- /**
117
- * @param isUse Optional boolean indicating whether this get() should be considered a "use" of the
118
- * entry (for determining least recently used). Defaults to true.
119
- * @returns undefined if there is no entry matching the given key.
120
- */
121
- get(k, isUse = true) {
122
- if (!this._cache.has(k)) return;
123
- const v = this._cache.get(k);
124
- if (isUse) {
125
- this._cache.delete(k);
126
- this._cache.set(k, v);
127
- }
128
- return v;
129
- }
130
- /**
131
- * Adds or updates an entry in the cache. This marks the entry as the most recently used entry.
132
- */
133
- set(k, v) {
134
- this._cache.delete(k);
135
- this._cache.set(k, v);
136
- this.evictOld();
137
- }
138
- /**
139
- * Evicts the oldest evictable entries until the number of entries is equal to or less than the
140
- * cache's capacity. This method is automatically called by set(). Call this if you need to evict
141
- * newly evictable entries before the next call to set().
142
- */
143
- evictOld() {
144
- for (const [k, v] of this._cache.entries()) {
145
- if (this._cache.size <= this._capacity) break;
146
- if (!this._evictable(k, v)) continue;
147
- this._cache.delete(k);
148
- }
149
- }
150
- };
151
- var SelfContainedPromise = class extends Promise {
152
- constructor(executor = null) {
153
- let done;
154
- super((resolve, reject) => {
155
- done = (err, val) => err != null ? reject(err) : resolve(val);
156
- if (executor != null) executor(resolve, reject);
157
- });
158
- this.done = done;
159
- }
160
- };
161
- const defaultSettings = {
162
- bulkLimit: 0,
163
- cache: 1e4,
164
- writeInterval: 100,
165
- json: true,
166
- charset: "utf8mb4"
167
- };
168
- const Database$1 = class {
169
- /**
170
- * @param wrappedDB The Database that should be wrapped
171
- * @param settings (optional) The settings that should be applied to the wrapper
172
- */
173
- constructor(wrappedDB, settings, logger) {
174
- if (wrappedDB.isAsync) this.wrappedDB = wrappedDB;
175
- else {
176
- this.wrappedDB = {};
177
- for (const fn of [
178
- "close",
179
- "doBulk",
180
- "findKeys",
181
- "get",
182
- "init",
183
- "remove",
184
- "set"
185
- ]) {
186
- const f = wrappedDB[fn];
187
- if (typeof f !== "function") continue;
188
- this.wrappedDB[fn] = util.default.promisify(f.bind(wrappedDB));
189
- }
190
- }
191
- this.logger = logger;
192
- this.settings = Object.freeze({
193
- ...defaultSettings,
194
- ...wrappedDB.settings || {},
195
- ...settings || {}
196
- });
197
- this.buffer = new LRU(this.settings.cache, (k, v) => !v.dirty && !v.writingInProgress);
198
- this._flushPaused = null;
199
- this._locks = /* @__PURE__ */ new Map();
200
- this.metrics = {
201
- lockAwaits: 0,
202
- lockAcquires: 0,
203
- lockReleases: 0,
204
- reads: 0,
205
- readsFailed: 0,
206
- readsFinished: 0,
207
- readsFromCache: 0,
208
- readsFromDb: 0,
209
- readsFromDbFailed: 0,
210
- readsFromDbFinished: 0,
211
- writes: 0,
212
- writesFailed: 0,
213
- writesFinished: 0,
214
- writesObsoleted: 0,
215
- writesToDb: 0,
216
- writesToDbFailed: 0,
217
- writesToDbFinished: 0,
218
- writesToDbRetried: 0
219
- };
220
- this.flushInterval = this.settings.writeInterval > 0 ? setInterval(() => this.flush(), this.settings.writeInterval) : null;
221
- }
222
- async _lock(key) {
223
- while (true) {
224
- const l = this._locks.get(key);
225
- if (l == null) break;
226
- ++this.metrics.lockAwaits;
227
- await l;
228
- }
229
- ++this.metrics.lockAcquires;
230
- this._locks.set(key, new SelfContainedPromise());
231
- }
232
- async _unlock(key) {
233
- ++this.metrics.lockReleases;
234
- this._locks.get(key).done();
235
- this._locks.delete(key);
236
- }
237
- _pauseFlush() {
238
- if (this._flushPaused == null) {
239
- this._flushPaused = new SelfContainedPromise();
240
- this._flushPaused.count = 0;
241
- }
242
- ++this._flushPaused.count;
243
- }
244
- _resumeFlush() {
245
- if (--this._flushPaused.count > 0) return;
246
- this._flushPaused.done();
247
- this._flushPaused = null;
248
- }
249
- /**
250
- * wraps the init function of the original DB
251
- */
252
- async init() {
253
- await this.wrappedDB.init();
254
- }
255
- /**
256
- * wraps the close function of the original DB
257
- */
258
- async close() {
259
- clearInterval(this.flushInterval);
260
- await this.flush();
261
- await this.wrappedDB.close();
262
- this.wrappedDB = null;
263
- }
264
- /**
265
- * Gets the value trough the wrapper.
266
- */
267
- async get(key) {
268
- let v;
269
- await this._lock(key);
270
- try {
271
- v = await this._getLocked(key);
272
- } finally {
273
- this._unlock(key);
274
- }
275
- return clone(v);
276
- }
277
- async _getLocked(key) {
278
- ++this.metrics.reads;
279
- try {
280
- const entry = this.buffer.get(key);
281
- if (entry != null) {
282
- ++this.metrics.readsFromCache;
283
- if (this.logger.isDebugEnabled()) this.logger.debug(`GET - ${key} - ${JSON.stringify(entry.value)} - from ${entry.dirty ? "dirty buffer" : "cache"}`);
284
- return entry.value;
285
- }
286
- let value;
287
- ++this.metrics.readsFromDb;
288
- try {
289
- value = await this.wrappedDB.get(key);
290
- } catch (err) {
291
- ++this.metrics.readsFromDbFailed;
292
- throw err;
293
- } finally {
294
- ++this.metrics.readsFromDbFinished;
295
- }
296
- if (this.settings.json) try {
297
- value = JSON.parse(value);
298
- } catch (err) {
299
- this.logger.error(`JSON-PROBLEM:${value}`);
300
- throw err;
301
- }
302
- if (this.settings.cache > 0) this.buffer.set(key, {
303
- value,
304
- dirty: null,
305
- writingInProgress: false
306
- });
307
- if (this.logger.isDebugEnabled()) this.logger.debug(`GET - ${key} - ${JSON.stringify(value)} - from database `);
308
- return value;
309
- } catch (err) {
310
- ++this.metrics.readsFailed;
311
- throw err;
312
- } finally {
313
- ++this.metrics.readsFinished;
314
- }
315
- }
316
- /**
317
- * Find keys function searches the db sets for matching entries and
318
- * returns the key entries via callback.
319
- */
320
- async findKeys(key, notKey) {
321
- await this.flush();
322
- const keyValues = await this.wrappedDB.findKeys(key, notKey);
323
- if (this.logger.isDebugEnabled()) this.logger.debug(`GET - ${key}-${notKey} - ${JSON.stringify(keyValues)} - from database `);
324
- return clone(keyValues);
325
- }
326
- /**
327
- * Remove a record from the database
328
- */
329
- async remove(key) {
330
- if (this.logger.isDebugEnabled()) this.logger.debug(`DELETE - ${key} - from database `);
331
- await this.set(key, null);
332
- }
333
- /**
334
- * Sets the value trough the wrapper
335
- */
336
- async set(key, value) {
337
- value = clone(value);
338
- let p;
339
- this._pauseFlush();
340
- try {
341
- await this._lock(key);
342
- try {
343
- p = this._setLocked(key, value);
344
- } finally {
345
- this._unlock(key);
346
- }
347
- } finally {
348
- this._resumeFlush();
349
- }
350
- await p;
351
- }
352
- async _setLocked(key, value) {
353
- ++this.metrics.writes;
354
- try {
355
- let entry = this.buffer.get(key);
356
- if (!entry || entry.writingInProgress) entry = {};
357
- else if (entry.dirty) ++this.metrics.writesObsoleted;
358
- entry.value = value;
359
- if (!entry.dirty) entry.dirty = new SelfContainedPromise();
360
- this.buffer.set(key, entry);
361
- const buffered = this.settings.writeInterval > 0;
362
- if (this.logger.isDebugEnabled()) this.logger.debug(`SET - ${key} - ${JSON.stringify(value)} - to ${buffered ? "buffer" : "database"}`);
363
- if (!buffered) this._write([[key, entry]]);
364
- await entry.dirty;
365
- } catch (err) {
366
- ++this.metrics.writesFailed;
367
- throw err;
368
- } finally {
369
- ++this.metrics.writesFinished;
370
- }
371
- }
372
- /**
373
- * Sets a subvalue
374
- */
375
- async setSub(key, sub, value) {
376
- value = clone(value);
377
- if (this.logger.isDebugEnabled()) this.logger.debug(`SETSUB - ${key}${JSON.stringify(sub)} - ${JSON.stringify(value)}`);
378
- let p;
379
- this._pauseFlush();
380
- try {
381
- await this._lock(key);
382
- try {
383
- let base;
384
- try {
385
- const fullValue = await this._getLocked(key);
386
- base = { fullValue };
387
- const ptr = {
388
- obj: base,
389
- prop: "fullValue"
390
- };
391
- for (let i = 0; i < sub.length; i++) {
392
- if (sub[i] === "__proto__") throw new Error("Modifying object prototype is not supported for security reasons");
393
- let o = ptr.obj[ptr.prop];
394
- if (o == null) ptr.obj[ptr.prop] = o = {};
395
- if (typeof o !== "object") throw new TypeError(`Cannot set property ${JSON.stringify(sub[i])} on non-object ${JSON.stringify(o)} (key: ${JSON.stringify(key)} value in db: ${JSON.stringify(fullValue)} sub: ${JSON.stringify(sub.slice(0, i + 1))})`);
396
- ptr.obj = ptr.obj[ptr.prop];
397
- ptr.prop = sub[i];
398
- }
399
- if (value == null) delete ptr.obj[ptr.prop];
400
- else ptr.obj[ptr.prop] = value;
401
- } catch (err) {
402
- ++this.metrics.writes;
403
- ++this.metrics.writesFailed;
404
- ++this.metrics.writesFinished;
405
- throw err;
406
- }
407
- p = this._setLocked(key, base.fullValue);
408
- } finally {
409
- await this._unlock(key);
410
- }
411
- } finally {
412
- this._resumeFlush();
413
- }
414
- await p;
415
- }
416
- /**
417
- * Returns a sub value of the object
418
- * @param sub is a array, for example if you want to access object.test.bla, the array is ["test",
419
- * "bla"]
420
- */
421
- async getSub(key, sub) {
422
- await this._lock(key);
423
- try {
424
- let v = await this._getLocked(key);
425
- for (const k of sub) {
426
- if (typeof v !== "object" || v != null && !Object.prototype.hasOwnProperty.call(v, k) || k === "__proto__") v = null;
427
- if (v == null) break;
428
- v = v[k];
429
- }
430
- if (this.logger.isDebugEnabled()) this.logger.debug(`GETSUB - ${key}${JSON.stringify(sub)} - ${JSON.stringify(v)}`);
431
- return clone(v);
432
- } finally {
433
- this._unlock(key);
434
- }
435
- }
436
- /**
437
- * Writes all dirty values to the database
438
- */
439
- async flush() {
440
- if (this._flushDone == null) this._flushDone = (async () => {
441
- while (true) {
442
- while (this._flushPaused != null) await this._flushPaused;
443
- const dirtyEntries = [];
444
- for (const entry of this.buffer) if (entry[1].dirty && !entry[1].writingInProgress) {
445
- dirtyEntries.push(entry);
446
- if (this.settings.bulkLimit && dirtyEntries.length >= this.settings.bulkLimit) break;
447
- }
448
- if (dirtyEntries.length === 0) return;
449
- await this._write(dirtyEntries);
450
- }
451
- })();
452
- await this._flushDone;
453
- this._flushDone = null;
454
- }
455
- async _write(dirtyEntries) {
456
- const markDone = (entry, err) => {
457
- if (entry.writingInProgress) {
458
- entry.writingInProgress = false;
459
- if (err != null) ++this.metrics.writesToDbFailed;
460
- ++this.metrics.writesToDbFinished;
461
- }
462
- entry.dirty.done(err);
463
- entry.dirty = null;
464
- };
465
- const ops = [];
466
- const entries = [];
467
- for (const [key, entry] of dirtyEntries) {
468
- let value = entry.value;
469
- try {
470
- value = this.settings.json && value != null ? JSON.stringify(value) : clone(value);
471
- } catch (err) {
472
- markDone(entry, err);
473
- continue;
474
- }
475
- entry.writingInProgress = true;
476
- ops.push({
477
- type: value == null ? "remove" : "set",
478
- key,
479
- value
480
- });
481
- entries.push(entry);
482
- }
483
- if (ops.length === 0) return;
484
- this.metrics.writesToDb += ops.length;
485
- const writeOneOp = async (op, entry) => {
486
- let writeErr = null;
487
- try {
488
- switch (op.type) {
489
- case "remove":
490
- await this.wrappedDB.remove(op.key);
491
- break;
492
- case "set":
493
- await this.wrappedDB.set(op.key, op.value);
494
- break;
495
- default: throw new Error(`unsupported operation type: ${op.type}`);
496
- }
497
- } catch (err) {
498
- writeErr = err || new Error(err);
499
- }
500
- markDone(entry, writeErr);
501
- };
502
- if (ops.length === 1) await writeOneOp(ops[0], entries[0]);
503
- else {
504
- let success = false;
505
- try {
506
- await this.wrappedDB.doBulk(ops);
507
- success = true;
508
- } catch (err) {
509
- this.logger.error(`Bulk write of ${ops.length} ops failed, retrying individually: ${err.stack || err}`);
510
- this.metrics.writesToDbRetried += ops.length;
511
- await Promise.all(ops.map(async (op, i) => await writeOneOp(op, entries[i])));
512
- }
513
- if (success) entries.forEach((entry) => markDone(entry, null));
514
- }
515
- this.buffer.evictOld();
516
- }
517
- };
518
- const clone = (obj, key = "") => {
519
- if (null == obj || "object" !== typeof obj) return obj;
520
- if (typeof obj.toJSON === "function") return clone(obj.toJSON(key));
521
- if (obj instanceof Date) {
522
- const copy = /* @__PURE__ */ new Date();
523
- copy.setTime(obj.getTime());
524
- return copy;
525
- }
526
- if (obj instanceof Array) {
527
- const copy = [];
528
- for (let i = 0, len = obj.length; i < len; ++i) copy[i] = clone(obj[i], String(i));
529
- return copy;
530
- }
531
- if (obj instanceof Object) {
532
- const copy = {};
533
- for (const attr in obj) if (Object.prototype.hasOwnProperty.call(obj, attr)) copy[attr] = clone(obj[attr], attr);
534
- return copy;
535
- }
536
- throw new Error("Unable to copy obj! Its type isn't supported.");
537
- };
538
- //#endregion
539
- //#region lib/logging.ts
540
- const normalizeLogger = (logger) => {
541
- const logLevelsUsed = [
542
- "debug",
543
- "info",
544
- "warn",
545
- "error"
546
- ];
547
- logger = Object.create(logger || {});
548
- for (const level of logLevelsUsed) {
549
- const enabledFnName = `is${level.charAt(0).toUpperCase() + level.slice(1)}Enabled`;
550
- if (typeof logger[level] !== "function") {
551
- logger[level] = () => {};
552
- logger[enabledFnName] = () => false;
553
- } else if (typeof logger[enabledFnName] !== "function") logger[enabledFnName] = () => true;
554
- }
555
- return logger;
556
- };
557
- //#endregion
558
- //#region lib/AbstractDatabase.ts
559
- const nullLogger = normalizeLogger(null);
560
- const simpleGlobToRegExp = (s) => s.replace(/[.+?^${}()|[\]\\]/g, "\\$&").replace(/\*/g, ".*");
561
- var AbstractDatabase = class {
562
- logger;
563
- settings;
564
- constructor(settings) {
565
- if (new.target === module.exports) throw new TypeError("cannot instantiate Abstract Database directly");
566
- for (const fn of [
567
- "init",
568
- "close",
569
- "get",
570
- "findKeys",
571
- "remove",
572
- "set"
573
- ]) if (typeof this[fn] !== "function") throw new TypeError(`method ${fn} not defined`);
574
- this.logger = nullLogger;
575
- this.settings = settings;
576
- }
577
- /**
578
- * For findKey regex. Used by document dbs like mongodb or dirty.
579
- */
580
- createFindRegex(key, notKey) {
581
- let regex = `^(?=${simpleGlobToRegExp(key)}$)`;
582
- if (notKey != null) regex += `(?!${simpleGlobToRegExp(notKey)}$)`;
583
- return new RegExp(regex);
584
- }
585
- doBulk(operations, cb) {
586
- throw new Error("the doBulk method must be implemented if write caching is enabled");
587
- }
588
- get isAsync() {
589
- return false;
590
- }
591
- };
592
- //#endregion
593
- //#region databases/cassandra_db.ts
594
- /**
595
- * Licensed under the Apache License, Version 2.0 (the "License");
596
- * you may not use this file except in compliance with the License.
597
- * You may obtain a copy of the License at
598
- *
599
- * http://www.apache.org/licenses/LICENSE-2.0
600
- *
601
- * Unless required by applicable law or agreed to in writing, software
602
- * distributed under the License is distributed on an "AS-IS" BASIS,
603
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
604
- * See the License for the specific language governing permissions and
605
- * limitations under the License.
606
- */
607
- var Cassandra_db = class extends AbstractDatabase {
608
- client;
609
- pool;
610
- /**
611
- * @param {Object} settings The required settings object to initiate the Cassandra database
612
- * @param {String[]} settings.clientOptions See
613
- * http://www.datastax.com/drivers/nodejs/2.0/global.html#ClientOptions for a full set of
614
- * options that can be used
615
- * @param {String} settings.columnFamily The column family that should be used to store data. The
616
- * column family will be created if it doesn't exist
617
- * @param {Function} [settings.logger] Function that will be used to pass on log events emitted by
618
- * the Cassandra driver. See https://github.com/datastax/nodejs-driver#logging for more
619
- * information
620
- */
621
- constructor(settings) {
622
- super(settings);
623
- if (!settings.clientOptions) throw new Error("The Cassandra client options should be defined");
624
- if (!settings.columnFamily) throw new Error("The Cassandra column family should be defined");
625
- this.settings = { database: settings.database };
626
- this.settings.clientOptions = settings.clientOptions;
627
- this.settings.columnFamily = settings.columnFamily;
628
- this.settings.logger = settings.logger;
629
- }
630
- /**
631
- * Initializes the Cassandra client, connects to Cassandra and creates the CF if it didn't exist
632
- * already
633
- *
634
- * @param {Function} callback Standard callback method.
635
- * @param {Error} callback.err An error object (if any.)
636
- */
637
- init(callback) {
638
- this.client = new cassandra_driver.Client(this.settings.clientOptions);
639
- if (this.settings.logger) this.client.on("log", this.settings.logger);
640
- this.client.execute("SELECT columnfamily_name FROM system.schema_columnfamilies WHERE keyspace_name = ?", [this.settings.clientOptions.keyspace], (err, result) => {
641
- if (err) return callback(err);
642
- let isDefined = false;
643
- const length = result.rows.length;
644
- for (let i = 0; i < length; i++) if (result.rows[i].columnfamily_name === this.settings.columnFamily) {
645
- isDefined = true;
646
- break;
647
- }
648
- if (isDefined) return callback(null);
649
- else {
650
- const cql = `CREATE COLUMNFAMILY "${this.settings.columnFamily}" (key text PRIMARY KEY, data text)`;
651
- this.client && this.client.execute(cql, callback);
652
- }
653
- });
654
- }
655
- /**
656
- * Gets a value from Cassandra
657
- *
658
- * @param {String} key The key for which the value should be retrieved
659
- * @param {Function} callback Standard callback method
660
- * @param {Error} callback.err An error object, if any
661
- * @param {String} callback.value The value for the given key (if any)
662
- */
663
- get(key, callback) {
664
- const cql = `SELECT data FROM "${this.settings.columnFamily}" WHERE key = ?`;
665
- this.client && this.client.execute(cql, [key], (err, result) => {
666
- if (err) return callback(err);
667
- if (!result.rows || result.rows.length === 0) return callback(null, null);
668
- return callback(null, result.rows[0].data);
669
- });
670
- }
671
- /**
672
- * Cassandra has no native `findKeys` method. This function implements a naive filter by
673
- * retrieving *all* the keys and filtering those. This should obviously be used with the utmost
674
- * care and is probably not something you want to run in production.
675
- *
676
- * @param {String} key The filter for keys that should match
677
- * @param {String} [notKey] The filter for keys that shouldn't match
678
- * @param {Function} callback Standard callback method
679
- * @param {Error} callback.err An error object, if any
680
- * @param {String[]} callback.keys An array of keys that match the specified filters
681
- */
682
- findKeys(key, notKey, callback) {
683
- let cql = null;
684
- if (!notKey) {
685
- cql = `SELECT key FROM "${this.settings.columnFamily}"`;
686
- this.client && this.client.execute(cql, (err, result) => {
687
- if (err) return callback(err);
688
- const regex = new RegExp(`^${key.replace(/\*/g, ".*")}$`);
689
- const keys = [];
690
- result.rows.forEach((row) => {
691
- if (regex.test(row.key)) keys.push(row.key);
692
- });
693
- return callback(null, keys);
694
- });
695
- } else if (notKey === "*:*:*") {
696
- const matches = /^([^:]+):\*$/.exec(key);
697
- if (matches) {
698
- cql = `SELECT * from "${this.settings.columnFamily}" WHERE key = ?`;
699
- this.client && this.client.execute(cql, [`ueberdb:keys:${matches[1]}`], (err, result) => {
700
- if (err) return callback(err);
701
- if (!result.rows || result.rows.length === 0) return callback(null, []);
702
- return callback(null, result.rows.map((row) => row.data));
703
- });
704
- } else return callback(/* @__PURE__ */ new Error("Cassandra db only supports key patterns like pad:* when notKey is set to *:*:*"), null);
705
- } else return callback(/* @__PURE__ */ new Error("Cassandra db currently only supports *:*:* as notKey"), null);
706
- }
707
- /**
708
- * Sets a value for a key
709
- *
710
- * @param {String} key The key to set
711
- * @param {String} value The value associated to this key
712
- * @param {Function} callback Standard callback method
713
- * @param {Error} callback.err An error object, if any
714
- */
715
- set(key, value, callback) {
716
- this.doBulk([{
717
- type: "set",
718
- key,
719
- value
720
- }], callback);
721
- }
722
- /**
723
- * Removes a key and it's value from the column family
724
- *
725
- * @param {String} key The key to remove
726
- * @param {Function} callback Standard callback method
727
- * @param {Error} callback.err An error object, if any
728
- */
729
- remove(key, callback) {
730
- this.doBulk([{
731
- type: "remove",
732
- key
733
- }], callback);
734
- }
735
- /**
736
- * Performs multiple operations in one action
737
- *
738
- * @param {Object[]} bulk The set of operations that should be performed
739
- * @param {Function} callback Standard callback method
740
- * @param {Error} callback.err An error object, if any
741
- */
742
- doBulk(bulk, callback) {
743
- const queries = [];
744
- bulk.forEach((operation) => {
745
- const matches = /^([^:]+):([^:]+)$/.exec(operation.key);
746
- if (operation.type === "set") {
747
- queries.push({
748
- query: `UPDATE "${this.settings.columnFamily}" SET data = ? WHERE key = ?`,
749
- params: [operation.value, operation.key]
750
- });
751
- if (matches) queries.push({
752
- query: `UPDATE "${this.settings.columnFamily}" SET data = ? WHERE key = ?`,
753
- params: ["1", `ueberdb:keys:${matches[1]}`]
754
- });
755
- } else if (operation.type === "remove") {
756
- queries.push({
757
- query: `DELETE FROM "${this.settings.columnFamily}" WHERE key=?`,
758
- params: [operation.key]
759
- });
760
- if (matches) queries.push({
761
- query: `DELETE FROM "${this.settings.columnFamily}" WHERE key = ?`,
762
- params: [`ueberdb:keys:${matches[1]}`]
763
- });
764
- }
765
- });
766
- this.client && this.client.batch(queries, { prepare: true }, callback);
767
- }
768
- /**
769
- * Closes the Cassandra connection
770
- *
771
- * @param {Function} callback Standard callback method
772
- * @param {Error} callback.err Error object in case something goes wrong
773
- */
774
- close(callback) {
775
- this.pool.shutdown(callback);
776
- }
777
- };
778
- //#endregion
779
- //#region databases/couch_db.ts
780
- /**
781
- * 2012 Max 'Azul' Wiehle
782
- *
783
- * Licensed under the Apache License, Version 2.0 (the "License");
784
- * you may not use this file except in compliance with the License.
785
- * You may obtain a copy of the License at
786
- *
787
- * http://www.apache.org/licenses/LICENSE-2.0
788
- *
789
- * Unless required by applicable law or agreed to in writing, software
790
- * distributed under the License is distributed on an "AS-IS" BASIS,
791
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
792
- * See the License for the specific language governing permissions and
793
- * limitations under the License.
794
- */
795
- var Couch_db = class extends AbstractDatabase {
796
- agent;
797
- db;
798
- constructor(settings) {
799
- super(settings);
800
- this.agent = null;
801
- this.db = null;
802
- this.settings = settings;
803
- this.settings.cache = 1e3;
804
- this.settings.writeInterval = 100;
805
- this.settings.json = false;
806
- }
807
- get isAsync() {
808
- return true;
809
- }
810
- async init() {
811
- this.agent = new http.default.Agent({
812
- keepAlive: true,
813
- maxSockets: this.settings.maxListeners || 1
814
- });
815
- const client = (0, nano.default)({
816
- url: `http://${this.settings.host}:${this.settings.port}`,
817
- requestDefaults: { agent: this.agent }
818
- });
819
- if (this.settings.user && this.settings.password) await client.auth(this.settings.user, this.settings.password);
820
- try {
821
- await client.db.get(this.settings.database);
822
- } catch (err) {
823
- if (err.statusCode !== 404) throw err;
824
- await client.db.create(this.settings.database);
825
- }
826
- this.db = client.use(this.settings.database);
827
- }
828
- async get(key) {
829
- let doc;
830
- try {
831
- if (this.db) doc = await this.db.get(key);
832
- } catch (err) {
833
- if (err.statusCode === 404) return null;
834
- throw err;
835
- }
836
- if (doc && "value" in doc) return doc.value;
837
- return "";
838
- }
839
- async findKeys(key, notKey) {
840
- const pfxLen = key.indexOf("*");
841
- if (!this.db) return;
842
- const pfx = pfxLen < 0 ? key : key.slice(0, pfxLen);
843
- return (await this.db.find({
844
- selector: { _id: pfxLen < 0 ? pfx : {
845
- $gte: pfx,
846
- $lte: `${pfx}\ufff0`,
847
- $regex: this.createFindRegex(key, notKey).source
848
- } },
849
- fields: ["_id"]
850
- })).docs.map((doc) => doc._id);
851
- }
852
- async set(key, value) {
853
- let doc;
854
- if (!this.db) return;
855
- try {
856
- doc = await this.db.get(key);
857
- } catch (err) {
858
- if (err.statusCode !== 404) throw err;
859
- }
860
- await this.db.insert({
861
- _id: key,
862
- value,
863
- ...doc == null ? {} : { _rev: doc._rev }
864
- });
865
- }
866
- async remove(key) {
867
- let header;
868
- if (!this.db) return;
869
- try {
870
- header = await this.db.head(key);
871
- } catch (err) {
872
- if (err.statusCode === 404) return;
873
- throw err;
874
- }
875
- const etag = JSON.parse(header.etag);
876
- await this.db.destroy(key, etag);
877
- }
878
- async doBulk(bulk) {
879
- if (!this.db) return;
880
- const keys = bulk.map((op) => op.key);
881
- const revs = {};
882
- for (const { key, value } of (await this.db.fetchRevs({ keys })).rows) if (value != null) revs[key] = value.rev;
883
- const setters = [];
884
- for (const item of bulk) {
885
- const set = {
886
- _id: item.key,
887
- _rev: void 0,
888
- _deleted: false,
889
- value: ""
890
- };
891
- if (revs[item.key] != null) set._rev = revs[item.key];
892
- if (item.type === "set") set.value = item.value;
893
- if (item.type === "remove") set._deleted = true;
894
- setters.push(set);
895
- }
896
- await this.db.bulk({ docs: setters });
897
- }
898
- async close() {
899
- this.db = null;
900
- if (this.agent) this.agent.destroy();
901
- this.agent = null;
902
- }
903
- };
904
- //#endregion
905
- //#region databases/dirty_db.ts
906
- /**
907
- * 2011 Peter 'Pita' Martischka
908
- *
909
- * Licensed under the Apache License, Version 2.0 (the "License");
910
- * you may not use this file except in compliance with the License.
911
- * You may obtain a copy of the License at
912
- *
913
- * http://www.apache.org/licenses/LICENSE-2.0
914
- *
915
- * Unless required by applicable law or agreed to in writing, software
916
- * distributed under the License is distributed on an "AS-IS" BASIS,
917
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
918
- * See the License for the specific language governing permissions and
919
- * limitations under the License.
920
- */
921
- var dirty_db_default = class extends AbstractDatabase {
922
- db;
923
- constructor(settings) {
924
- super(settings);
925
- this.db = null;
926
- if (!settings || !settings.filename) settings = { filename: null };
927
- this.settings = settings;
928
- this.settings.cache = 0;
929
- this.settings.writeInterval = 0;
930
- this.settings.json = false;
931
- }
932
- init(callback) {
933
- this.db = new dirty_ts.default(this.settings.filename);
934
- this.db.on("load", () => {
935
- callback();
936
- });
937
- }
938
- get(key, callback) {
939
- callback(null, this.db.get(key));
940
- }
941
- findKeys(key, notKey, callback) {
942
- const keys = [];
943
- const regex = this.createFindRegex(key, notKey);
944
- this.db.forEach((key) => {
945
- if (key.search(regex) !== -1) keys.push(key);
946
- });
947
- callback(null, keys);
948
- }
949
- set(key, value, callback) {
950
- this.db.set(key, value, callback);
951
- }
952
- remove(key, callback) {
953
- this.db.rm(key, callback);
954
- }
955
- close(callback) {
956
- this.db.close();
957
- this.db = null;
958
- if (callback) callback();
959
- }
960
- };
961
- //#endregion
962
- //#region databases/dirty_git_db.ts
963
- /**
964
- * 2011 Peter 'Pita' Martischka
965
- *
966
- * Licensed under the Apache License, Version 2.0 (the "License");
967
- * you may not use this file except in compliance with the License.
968
- * You may obtain a copy of the License at
969
- *
970
- * http://www.apache.org/licenses/LICENSE-2.0
971
- *
972
- * Unless required by applicable law or agreed to in writing, software
973
- * distributed under the License is distributed on an "AS-IS" BASIS,
974
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
975
- * See the License for the specific language governing permissions and
976
- * limitations under the License.
977
- */
978
- var dirty_git_db_default = class extends AbstractDatabase {
979
- db;
980
- constructor(settings) {
981
- super(settings);
982
- this.db = null;
983
- if (!settings || !settings.filename) settings = {};
984
- this.settings = settings;
985
- this.settings.cache = 0;
986
- this.settings.writeInterval = 0;
987
- this.settings.json = false;
988
- }
989
- init(callback) {
990
- this.db = new dirty_ts.default(this.settings.filename);
991
- this.db.on("load", (err) => {
992
- callback();
993
- });
994
- }
995
- get(key, callback) {
996
- callback(null, this.db.get(key));
997
- }
998
- findKeys(key, notKey, callback) {
999
- const keys = [];
1000
- const regex = this.createFindRegex(key, notKey);
1001
- this.db.forEach((key, val) => {
1002
- if (key.search(regex) !== -1) keys.push(key);
1003
- });
1004
- callback(null, keys);
1005
- }
1006
- set(key, value, callback) {
1007
- this.db.set(key, value, callback);
1008
- (0, simple_git.simpleGit)((0, node_path.dirname)(this.settings.filename)).silent(true).add("./*.db").commit("Automated commit...").push([
1009
- "-u",
1010
- "origin",
1011
- "master"
1012
- ], () => console.debug("Stored git commit"));
1013
- }
1014
- remove(key, callback) {
1015
- this.db.rm(key, callback);
1016
- }
1017
- close(callback) {
1018
- this.db.close();
1019
- if (callback) callback();
1020
- }
1021
- };
1022
- //#endregion
1023
- //#region databases/elasticsearch_db.ts
1024
- /**
1025
- * 2015 Visionist, Inc.
1026
- *
1027
- * Licensed under the Apache License, Version 2.0 (the "License");
1028
- * you may not use this file except in compliance with the License.
1029
- * You may obtain a copy of the License at
1030
- *
1031
- * http://www.apache.org/licenses/LICENSE-2.0
1032
- *
1033
- * Unless required by applicable law or agreed to in writing, software
1034
- * distributed under the License is distributed on an "AS-IS" BASIS,
1035
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1036
- * See the License for the specific language governing permissions and
1037
- * limitations under the License.
1038
- */
1039
- const schema = "2";
1040
- const keyToId = (key) => {
1041
- const keyBuf = buffer.Buffer.from(key);
1042
- return keyBuf.length > 512 ? (0, crypto.createHash)("sha512").update(keyBuf).digest("hex") : key;
1043
- };
1044
- const mappings = { properties: {
1045
- key: { type: "wildcard" },
1046
- value: {
1047
- type: "object",
1048
- enabled: false
1049
- }
1050
- } };
1051
- const legacyDocToSchema2Key = (index, id, type, v1BaseIndex) => {
1052
- const legacyType = typeof type === "string" && type !== "" && type !== "_doc" ? type : null;
1053
- if (v1BaseIndex && index !== v1BaseIndex) {
1054
- const parts = index.slice(v1BaseIndex.length + 1).split("-");
1055
- if (parts.length !== 2) throw new Error(`unable to migrate records from index ${index} due to data ambiguity`);
1056
- if (legacyType != null) return `${parts[0]}:${decodeURIComponent(legacyType)}:${parts[1]}:${id}`;
1057
- const idParts = id.split(":");
1058
- if (idParts.length !== 2) throw new Error(`unable to migrate records from index ${index} due to data ambiguity`);
1059
- return `${parts[0]}:${idParts[0]}:${parts[1]}:${idParts[1]}`;
1060
- }
1061
- if (legacyType != null) return `${legacyType}:${id}`;
1062
- const idParts = id.split(":");
1063
- if (idParts.length !== 2) throw new Error(`unable to migrate records from index ${index} due to missing legacy type metadata`);
1064
- return `${idParts[0]}:${idParts[1]}`;
1065
- };
1066
- const migrateToSchema2 = async (client, v1BaseIndex, v2Index, logger) => {
1067
- let recordsMigratedLastLogged = 0;
1068
- let recordsMigrated = 0;
1069
- const totals = /* @__PURE__ */ new Map();
1070
- logger.info(`Attempting elasticsearch record migration from schema v1 at base index ${v1BaseIndex} to schema v2 at index ${v2Index}...`);
1071
- const indices = await client.indices.get({ index: [v1BaseIndex, `${v1BaseIndex}-*-*`] });
1072
- const scrollIds = /* @__PURE__ */ new Map();
1073
- const q = [];
1074
- try {
1075
- for (const index of Object.keys(indices)) {
1076
- const res = await client.search({
1077
- index,
1078
- scroll: "10m"
1079
- });
1080
- scrollIds.set(index, res._scroll_id);
1081
- q.push({
1082
- index,
1083
- res
1084
- });
1085
- }
1086
- while (q.length) {
1087
- const { index, res: { hits: { hits, total: { value: total } } } } = q.shift();
1088
- if (hits.length === 0) continue;
1089
- totals.set(index, total);
1090
- const body = [];
1091
- for (const { _id, _type, _source: { val } } of hits) {
1092
- const key = legacyDocToSchema2Key(index, _id, _type, v1BaseIndex);
1093
- body.push({ index: { _id: keyToId(key) } }, {
1094
- key,
1095
- value: JSON.parse(val)
1096
- });
1097
- }
1098
- await client.bulk({
1099
- index: v2Index,
1100
- body
1101
- });
1102
- recordsMigrated += hits.length;
1103
- if (Math.floor(recordsMigrated / 100) > Math.floor(recordsMigratedLastLogged / 100)) {
1104
- const total = [...totals.values()].reduce((a, b) => a + b, 0);
1105
- logger.info(`Migrated ${recordsMigrated} records out of ${total}`);
1106
- recordsMigratedLastLogged = recordsMigrated;
1107
- }
1108
- q.push({
1109
- index,
1110
- res: await client.scroll({
1111
- scroll: "5m",
1112
- scroll_id: scrollIds.get(index)
1113
- })
1114
- });
1115
- }
1116
- logger.info(`Finished migrating ${recordsMigrated} records`);
1117
- } finally {
1118
- await Promise.all([...scrollIds.values()].map((scrollId) => client.clearScroll({ scroll_id: scrollId })));
1119
- }
1120
- };
1121
- var elasticsearch_db_default = class extends AbstractDatabase {
1122
- _client;
1123
- _index;
1124
- _indexClean;
1125
- _q;
1126
- constructor(settings) {
1127
- super(settings);
1128
- this._client = null;
1129
- this.settings = {
1130
- host: "127.0.0.1",
1131
- port: "9200",
1132
- base_index: "ueberes",
1133
- migrate_to_newer_schema: false,
1134
- api: "7.6",
1135
- ...settings || {},
1136
- json: false
1137
- };
1138
- this._index = `${this.settings.base_index}_s${schema}`;
1139
- this._q = { index: this._index };
1140
- this._indexClean = true;
1141
- }
1142
- get isAsync() {
1143
- return true;
1144
- }
1145
- async _refreshIndex() {
1146
- if (this._indexClean) return;
1147
- this._indexClean = true;
1148
- await this._client.indices.refresh(this._q);
1149
- }
1150
- /**
1151
- * Initialize the elasticsearch client, then ping the server to ensure that a
1152
- * connection was made.
1153
- */
1154
- async init() {
1155
- const client = new _elastic_elasticsearch.Client({ node: `http://${this.settings.host}:${this.settings.port}` });
1156
- await client.ping();
1157
- if (!await client.indices.exists({ index: this._index })) {
1158
- let tmpIndex;
1159
- const exists = await client.indices.exists({ index: this.settings.base_index });
1160
- if (exists && !this.settings.migrate_to_newer_schema) throw new Error(`Data exists under the legacy index (schema) named ${this.settings.base_index}. Set migrate_to_newer_schema to true to copy the existing data to a new index named ${this._index}.`);
1161
- let attempt = 0;
1162
- while (true) {
1163
- tmpIndex = `${this._index}_${exists ? "migrate_attempt_" : "i"}${attempt++}`;
1164
- if (!await client.indices.exists({ index: tmpIndex })) break;
1165
- }
1166
- await client.indices.create({
1167
- index: tmpIndex,
1168
- mappings
1169
- });
1170
- if (exists) await migrateToSchema2(client, this.settings.base_index, tmpIndex, this.logger);
1171
- await client.indices.putAlias({
1172
- index: tmpIndex,
1173
- name: this._index
1174
- });
1175
- }
1176
- const indices = Object.values(await client.indices.get({ index: this._index }));
1177
- (0, assert.equal)(indices.length, 1);
1178
- try {
1179
- assert.default.deepEqual(indices[0].mappings, mappings);
1180
- } catch (err) {
1181
- this.logger.warn(`Index ${this._index} mappings does not match expected; attempting to use index anyway. Details: ${err}`);
1182
- }
1183
- this._client = client;
1184
- }
1185
- /**
1186
- * This function provides read functionality to the database.
1187
- *
1188
- * @param {String} key Key
1189
- */
1190
- async get(key) {
1191
- const res = await this._client.get({
1192
- ...this._q,
1193
- id: keyToId(key)
1194
- }, { ignore: [404] });
1195
- if (!res.found) return null;
1196
- return res._source.value;
1197
- }
1198
- /**
1199
- * @param key Search key, which uses an asterisk (*) as the wild card.
1200
- * @param notKey Used to filter the result set
1201
- */
1202
- async findKeys(key, notKey) {
1203
- await this._refreshIndex();
1204
- const q = {
1205
- ...this._q,
1206
- body: { query: { bool: {
1207
- filter: { wildcard: { key: { value: key } } },
1208
- ...notKey == null ? {} : { must_not: { wildcard: { key: { value: notKey } } } }
1209
- } } }
1210
- };
1211
- const { hits } = await this._client.search(q);
1212
- return hits.hits.map((h) => h._source.key);
1213
- }
1214
- /**
1215
- * This function provides write functionality to the database.
1216
- *
1217
- * @param {String} key Record identifier.
1218
- * @param {JSON|String} value The value to store in the database.
1219
- */
1220
- async set(key, value) {
1221
- this._indexClean = false;
1222
- await this._client.index({
1223
- ...this._q,
1224
- id: keyToId(key),
1225
- body: {
1226
- key,
1227
- value
1228
- }
1229
- });
1230
- }
1231
- /**
1232
- * This function provides delete functionality to the database.
1233
- *
1234
- * The index, type, and ID will be parsed from the key, and this document will
1235
- * be deleted from the database.
1236
- *
1237
- * @param {String} key Record identifier.
1238
- */
1239
- async remove(key) {
1240
- this._indexClean = false;
1241
- await this._client.delete({
1242
- ...this._q,
1243
- id: keyToId(key)
1244
- }, { ignore: [404] });
1245
- }
1246
- /**
1247
- * This uses the bulk upload functionality of elasticsearch (url:port/_bulk).
1248
- *
1249
- * The CacheAndBufferLayer will periodically (every this.settings.writeInterval)
1250
- * flush writes that have already been done in the local cache out to the database.
1251
- *
1252
- * @param {Array} bulk An array of JSON data in the format:
1253
- * {"type":type, "key":key, "value":value}
1254
- */
1255
- async doBulk(bulk) {
1256
- const operations = [];
1257
- for (const { type, key, value } of bulk) {
1258
- this._indexClean = false;
1259
- switch (type) {
1260
- case "set":
1261
- operations.push({ index: { _id: keyToId(key) } });
1262
- operations.push({
1263
- key,
1264
- value
1265
- });
1266
- break;
1267
- case "remove":
1268
- operations.push({ delete: { _id: keyToId(key) } });
1269
- break;
1270
- default:
1271
- }
1272
- }
1273
- await this._client.bulk({
1274
- ...this._q,
1275
- body: operations
1276
- });
1277
- }
1278
- async close() {
1279
- if (this._client != null) this._client.close();
1280
- this._client = null;
1281
- }
1282
- };
1283
- //#endregion
1284
- //#region databases/memory_db.ts
1285
- var MemoryDB = class extends AbstractDatabase {
1286
- _data;
1287
- constructor(settings) {
1288
- super(settings);
1289
- this.settings = settings;
1290
- settings.json = false;
1291
- settings.cache = 0;
1292
- settings.writeInterval = 0;
1293
- this._data = null;
1294
- }
1295
- get isAsync() {
1296
- return true;
1297
- }
1298
- close() {
1299
- this._data = null;
1300
- }
1301
- findKeys(key, notKey) {
1302
- const regex = this.createFindRegex(key, notKey);
1303
- return [...this._data.keys()].filter((k) => regex.test(k));
1304
- }
1305
- get(key) {
1306
- return this._data.get(key);
1307
- }
1308
- init() {
1309
- this._data = this.settings.data || /* @__PURE__ */ new Map();
1310
- }
1311
- remove(key) {
1312
- this._data.delete(key);
1313
- }
1314
- set(key, value) {
1315
- this._data.set(key, value);
1316
- }
1317
- };
1318
- //#endregion
1319
- //#region databases/mock_db.ts
1320
- var mock_db_default = class extends events.default.EventEmitter {
1321
- settings;
1322
- mock;
1323
- constructor(settings) {
1324
- super();
1325
- this.settings = {
1326
- writeInterval: 1,
1327
- ...settings
1328
- };
1329
- settings.mock = this;
1330
- this.settings = settings;
1331
- }
1332
- close(cb) {
1333
- this.emit("close", cb);
1334
- }
1335
- doBulk(ops, cb) {
1336
- this.emit("doBulk", ops, cb);
1337
- }
1338
- findKeys(key, notKey, cb) {
1339
- this.emit("findKeys", key, notKey, cb);
1340
- }
1341
- get(key, cb) {
1342
- this.emit("get", key, cb);
1343
- }
1344
- async init(cb) {
1345
- this.emit("init", cb());
1346
- }
1347
- remove(key, cb) {
1348
- this.emit("remove", key, cb);
1349
- }
1350
- set(key, value, cb) {
1351
- this.emit("set", key, value, cb);
1352
- }
1353
- };
1354
- //#endregion
1355
- //#region databases/mongodb_db.ts
1356
- /**
1357
- * 2020 Sylchauf
1358
- *
1359
- * Licensed under the Apache License, Version 2.0 (the "License");
1360
- * you may not use this file except in compliance with the License.
1361
- * You may obtain a copy of the License at
1362
- *
1363
- * http://www.apache.org/licenses/LICENSE-2.0
1364
- *
1365
- * Unless required by applicable law or agreed to in writing, software
1366
- * distributed under the License is distributed on an "AS-IS" BASIS,
1367
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1368
- * See the License for the specific language governing permissions and
1369
- * limitations under the License.
1370
- */
1371
- var mongodb_db_default = class extends AbstractDatabase {
1372
- interval;
1373
- database;
1374
- client;
1375
- collection;
1376
- constructor(settings) {
1377
- super(settings);
1378
- this.settings = settings;
1379
- if (!this.settings.url) throw new Error("You must specify a mongodb url");
1380
- if (this.settings.database == null) this.settings.database = this.settings.dbName;
1381
- if (!this.settings.collection) this.settings.collection = "ueberdb";
1382
- }
1383
- clearPing() {
1384
- if (this.interval) clearInterval(this.interval[Symbol.toPrimitive]());
1385
- }
1386
- schedulePing() {
1387
- this.clearPing();
1388
- this.interval = setInterval(() => {
1389
- this.database.command({ ping: 1 });
1390
- }, 1e4);
1391
- }
1392
- init(callback) {
1393
- mongodb.MongoClient.connect(this.settings.url).then((v) => {
1394
- this.client = v;
1395
- this.database = v.db(this.settings.database);
1396
- this.schedulePing();
1397
- this.collection = this.database.collection(this.settings.collection);
1398
- callback(null);
1399
- }).catch((v) => {
1400
- callback(v);
1401
- });
1402
- }
1403
- get(key, callback) {
1404
- this.collection.findOne({ _id: key }).then((v) => {
1405
- callback(null, v && v.value);
1406
- }).catch((v) => {
1407
- console.log(v);
1408
- callback(v);
1409
- });
1410
- this.schedulePing();
1411
- }
1412
- findKeys(key, notKey, callback) {
1413
- const selector = { $and: [{ _id: { $regex: `${key.replace(/\*/g, "")}` } }] };
1414
- if (notKey) selector.$and.push({ _id: { $not: { $regex: `${notKey.replace(/\*/g, "")}` } } });
1415
- this.collection.find(selector).map((i) => i._id).toArray().then((r) => {
1416
- callback(null, r);
1417
- }).catch((v) => callback(v));
1418
- this.schedulePing();
1419
- }
1420
- set(key, value, callback) {
1421
- if (key.length > 100) callback("Your Key can only be 100 chars");
1422
- else this.collection.updateMany({ _id: key }, { $set: { value } }, { upsert: true }).then(() => callback(null)).catch((v) => callback(v));
1423
- this.schedulePing();
1424
- }
1425
- remove(key, callback) {
1426
- this.collection.deleteOne({ _id: key }).then((r) => callback(null, r)).catch((v) => callback(v));
1427
- this.schedulePing();
1428
- }
1429
- doBulk(bulk, callback) {
1430
- const bulkMongo = this.collection.initializeOrderedBulkOp();
1431
- for (const i in bulk) if (bulk[i].type === "set") bulkMongo.find({ _id: bulk[i].key }).upsert().updateOne({ $set: { value: bulk[i].value } });
1432
- else if (bulk[i].type === "remove") bulkMongo.find({ _id: bulk[i].key }).deleteOne();
1433
- bulkMongo.execute().then((res) => {
1434
- callback(null, res);
1435
- }).catch((error) => {
1436
- callback(error);
1437
- });
1438
- this.schedulePing();
1439
- }
1440
- close(callback) {
1441
- this.clearPing();
1442
- this.client.close().then((r) => callback(r));
1443
- }
1444
- };
1445
- //#endregion
1446
- //#region databases/mssql_db.ts
1447
- /**
1448
- * 2019 - exspecto@gmail.com
1449
- *
1450
- * Licensed under the Apache License, Version 2.0 (the "License");
1451
- * you may not use this file except in compliance with the License.
1452
- * You may obtain a copy of the License at
1453
- *
1454
- * http://www.apache.org/licenses/LICENSE-2.0
1455
- *
1456
- * Unless required by applicable law or agreed to in writing, software
1457
- * distributed under the License is distributed on an "AS-IS" BASIS,
1458
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1459
- * See the License for the specific language governing permissions and
1460
- * limitations under the License.
1461
- *
1462
- *
1463
- * Note: This requires MS SQL Server >= 2008 due to the usage of the MERGE statement
1464
- *
1465
- */
1466
- var MSSQL = class extends AbstractDatabase {
1467
- db;
1468
- constructor(settings) {
1469
- super(settings);
1470
- settings = settings || {};
1471
- if (settings.json != null) settings.parseJSON = settings.json;
1472
- settings.requestTimeout = 3e5;
1473
- settings.server = settings.host;
1474
- this.settings = settings;
1475
- this.settings.cache = 0;
1476
- this.settings.writeInterval = 0;
1477
- }
1478
- init(callback) {
1479
- const sqlCreate = "IF OBJECT_ID(N'dbo.store', N'U') IS NULL BEGIN CREATE TABLE [store] ( [key] NVARCHAR(100) PRIMARY KEY, [value] NTEXT NOT NULL ); END";
1480
- new mssql.default.ConnectionPool(this.settings).connect().then((pool) => {
1481
- this.db = pool;
1482
- new mssql.default.Request(this.db).query(sqlCreate, (err) => {
1483
- callback(err);
1484
- });
1485
- this.db.on("error", (err) => {
1486
- console.log(err);
1487
- });
1488
- });
1489
- }
1490
- get(key, callback) {
1491
- const request = new mssql.default.Request(this.db);
1492
- request.input("key", mssql.default.NVarChar(100), key);
1493
- request.query("SELECT [value] FROM [store] WHERE [key] = @key", (err, results) => {
1494
- let value = null;
1495
- if (!err && results && results.rowsAffected[0] === 1) value = results.recordset[0].value;
1496
- callback(err, value);
1497
- });
1498
- }
1499
- findKeys(key, notKey, callback) {
1500
- const request = new mssql.default.Request(this.db);
1501
- let query = "SELECT [key] FROM [store] WHERE [key] LIKE @key";
1502
- key = key.replace(/\*/g, "%");
1503
- request.input("key", mssql.default.NVarChar(100), key);
1504
- if (notKey != null) {
1505
- notKey = notKey.replace(/\*/g, "%");
1506
- request.input("notkey", mssql.default.NVarChar(100), notKey);
1507
- query += " AND [key] NOT LIKE @notkey";
1508
- }
1509
- request.query(query, (err, results) => {
1510
- const value = [];
1511
- if (!err && results && results.rowsAffected[0] > 0) for (let i = 0; i < results.recordset.length; i++) value.push(results.recordset[i].key);
1512
- callback(err, value);
1513
- });
1514
- }
1515
- set(key, value, callback) {
1516
- const request = new mssql.default.Request(this.db);
1517
- if (key.length > 100) callback("Your Key can only be 100 chars");
1518
- else {
1519
- const query = "MERGE [store] t USING (SELECT @key [key], @value [value]) s ON t.[key] = s.[key] WHEN MATCHED AND s.[value] IS NOT NULL THEN UPDATE SET t.[value] = s.[value] WHEN NOT MATCHED THEN INSERT ([key], [value]) VALUES (s.[key], s.[value]);";
1520
- request.input("key", mssql.default.NVarChar(100), key);
1521
- request.input("value", mssql.default.NText, value);
1522
- request.query(query, (err, info) => {
1523
- callback(err ? err.toString() : "");
1524
- });
1525
- }
1526
- }
1527
- remove(key, callback) {
1528
- const request = new mssql.default.Request(this.db);
1529
- request.input("key", mssql.default.NVarChar(100), key);
1530
- request.query("DELETE FROM [store] WHERE [key] = @key", callback);
1531
- }
1532
- doBulk(bulk, callback) {
1533
- const maxInserts = 100;
1534
- const request = new mssql.default.Request(this.db);
1535
- let firstReplace = true;
1536
- let firstRemove = true;
1537
- const replacements = [];
1538
- let removeSQL = "DELETE FROM [store] WHERE [key] IN (";
1539
- for (const i in bulk) if (bulk[i].type === "set") {
1540
- if (firstReplace) {
1541
- replacements.push("BEGIN TRANSACTION;");
1542
- firstReplace = false;
1543
- } else if (Number(i) % maxInserts === 0) replacements.push("\nCOMMIT TRANSACTION;\nBEGIN TRANSACTION;\n");
1544
- replacements.push(`MERGE [store] t USING (SELECT '${bulk[i].key}' [key], '${bulk[i].value}' [value]) s`, "ON t.[key] = s.[key]", "WHEN MATCHED AND s.[value] IS NOT NULL THEN UPDATE SET t.[value] = s.[value]", "WHEN NOT MATCHED THEN INSERT ([key], [value]) VALUES (s.[key], s.[value]);");
1545
- } else if (bulk[i].type === "remove") {
1546
- if (!firstRemove) removeSQL += ",";
1547
- firstRemove = false;
1548
- removeSQL += `'${bulk[i].key}'`;
1549
- }
1550
- removeSQL += ");";
1551
- replacements.push("COMMIT TRANSACTION;");
1552
- async.default.parallel([(callback) => {
1553
- if (!firstReplace) request.batch(replacements.join("\n"), (err, results) => {
1554
- if (err) callback(err);
1555
- callback(err, results);
1556
- });
1557
- else callback();
1558
- }, (callback) => {
1559
- if (!firstRemove) request.query(removeSQL, callback);
1560
- else callback();
1561
- }], (err, results) => {
1562
- if (err) callback(err);
1563
- callback(err, results);
1564
- });
1565
- }
1566
- close(callback) {
1567
- this.db && this.db.close(callback);
1568
- }
1569
- };
1570
- //#endregion
1571
- //#region databases/mysql_db.ts
1572
- /**
1573
- * 2011 Peter 'Pita' Martischka
1574
- *
1575
- * Licensed under the Apache License, Version 2.0 (the "License");
1576
- * you may not use this file except in compliance with the License.
1577
- * You may obtain a copy of the License at
1578
- *
1579
- * http://www.apache.org/licenses/LICENSE-2.0
1580
- *
1581
- * Unless required by applicable law or agreed to in writing, software
1582
- * distributed under the License is distributed on an "AS-IS" BASIS,
1583
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1584
- * See the License for the specific language governing permissions and
1585
- * limitations under the License.
1586
- */
1587
- var mysql_db_default = class extends AbstractDatabase {
1588
- _mysqlSettings;
1589
- _pool;
1590
- constructor(settings) {
1591
- super(settings);
1592
- this.logger = console;
1593
- this._mysqlSettings = {
1594
- charset: "utf8mb4",
1595
- ...settings
1596
- };
1597
- this.settings = {
1598
- engine: "InnoDB",
1599
- bulkLimit: 100,
1600
- json: true,
1601
- queryTimeout: 6e4
1602
- };
1603
- this._pool = null;
1604
- }
1605
- get isAsync() {
1606
- return true;
1607
- }
1608
- async _query(options) {
1609
- try {
1610
- return await new Promise((resolve, reject) => {
1611
- options = {
1612
- timeout: this.settings.queryTimeout,
1613
- ...options
1614
- };
1615
- this._pool && this._pool.query(options, (err, ...args) => err != null ? reject(err) : resolve(args));
1616
- });
1617
- } catch (err) {
1618
- this.logger.error(`${err.fatal ? "Fatal " : ""}MySQL error: ${err.stack || err}`);
1619
- throw err;
1620
- }
1621
- }
1622
- async init() {
1623
- if ("speeds" in this._mysqlSettings) delete this._mysqlSettings.speeds;
1624
- if ("filename" in this._mysqlSettings) delete this._mysqlSettings.filename;
1625
- this._pool = (0, mysql2.createPool)(this._mysqlSettings);
1626
- const { database, charset } = this._mysqlSettings;
1627
- const sqlCreate = `CREATE TABLE IF NOT EXISTS \`store\` ( \`key\` VARCHAR( 100 ) NOT NULL COLLATE utf8mb4_bin, \`value\` LONGTEXT COLLATE utf8mb4_bin NOT NULL , PRIMARY KEY ( \`key\` ) ) ENGINE=${this.settings.engine} CHARSET=utf8mb4 COLLATE=utf8mb4_bin;`;
1628
- const sqlAlter = "ALTER TABLE store MODIFY `key` VARCHAR(100) COLLATE utf8mb4_bin;";
1629
- await this._query({ sql: sqlCreate });
1630
- const dbCharSet = `SELECT DEFAULT_CHARACTER_SET_NAME, DEFAULT_COLLATION_NAME FROM INFORMATION_SCHEMA.SCHEMATA WHERE SCHEMA_NAME = '${database}'`;
1631
- let [result] = await this._query({ sql: dbCharSet });
1632
- result = JSON.parse(JSON.stringify(result));
1633
- if (result[0].DEFAULT_CHARACTER_SET_NAME !== charset) {
1634
- this.logger.error(`Database is not configured with charset ${charset} -- This may lead to crashes when certain characters are pasted in pads`);
1635
- this.logger.warn(result[0], charset);
1636
- }
1637
- if (result[0].DEFAULT_COLLATION_NAME.indexOf(charset) === -1) {
1638
- this.logger.error(`Database is not configured with collation name that includes ${charset} -- This may lead to crashes when certain characters are pasted in pads`);
1639
- this.logger.warn(result[0], charset, result[0].DEFAULT_COLLATION_NAME);
1640
- }
1641
- const tableCharSet = `SELECT CCSA.character_set_name AS character_set_name FROM information_schema.\`TABLES\` T,information_schema.\`COLLATION_CHARACTER_SET_APPLICABILITY\` CCSA WHERE CCSA.collation_name = T.table_collation AND T.table_schema = '${database}' AND T.table_name = 'store'`;
1642
- [result] = await this._query({ sql: tableCharSet });
1643
- if (!result[0]) this.logger.warn("Data has no character_set_name value -- This may lead to crashes when certain characters are pasted in pads");
1644
- if (result[0] && result[0].character_set_name !== charset) {
1645
- this.logger.error(`table is not configured with charset ${charset} -- This may lead to crashes when certain characters are pasted in pads`);
1646
- this.logger.warn(result[0], charset);
1647
- }
1648
- if (await this.get("MYSQL_MIGRATION_LEVEL") !== "1") {
1649
- await this._query({ sql: sqlAlter });
1650
- await this.set("MYSQL_MIGRATION_LEVEL", "1");
1651
- }
1652
- }
1653
- async get(key) {
1654
- const [results] = await this._query({
1655
- sql: "SELECT `value` FROM `store` WHERE `key` = ? AND BINARY `key` = ?",
1656
- values: [key, key]
1657
- });
1658
- return results.length === 1 ? results[0].value : null;
1659
- }
1660
- async findKeys(key, notKey) {
1661
- let query = "SELECT `key` FROM `store` WHERE `key` LIKE ?";
1662
- const params = [];
1663
- key = key.replace(/\*/g, "%");
1664
- params.push(key);
1665
- if (notKey != null) {
1666
- notKey = notKey.replace(/\*/g, "%");
1667
- query += " AND `key` NOT LIKE ?";
1668
- params.push(notKey);
1669
- }
1670
- const [results] = await this._query({
1671
- sql: query,
1672
- values: params
1673
- });
1674
- return results.map((val) => val.key);
1675
- }
1676
- async set(key, value) {
1677
- if (key.length > 100) throw new Error("Your Key can only be 100 chars");
1678
- await this._query({
1679
- sql: "REPLACE INTO `store` VALUES (?,?)",
1680
- values: [key, value]
1681
- });
1682
- }
1683
- async remove(key) {
1684
- await this._query({
1685
- sql: "DELETE FROM `store` WHERE `key` = ? AND BINARY `key` = ?",
1686
- values: [key, key]
1687
- });
1688
- }
1689
- async doBulk(bulk) {
1690
- const replaces = [];
1691
- const deletes = [];
1692
- for (const op of bulk) switch (op.type) {
1693
- case "set":
1694
- replaces.push([op.key, op.value]);
1695
- break;
1696
- case "remove":
1697
- deletes.push(op.key);
1698
- break;
1699
- default: throw new Error(`unknown op type: ${op.type}`);
1700
- }
1701
- await Promise.all([replaces.length ? this._query({
1702
- sql: "REPLACE INTO `store` VALUES ?;",
1703
- values: [replaces]
1704
- }) : null, deletes.length ? this._query({
1705
- sql: "DELETE FROM `store` WHERE `key` IN (?) AND BINARY `key` IN (?);",
1706
- values: [deletes, deletes]
1707
- }) : null]);
1708
- }
1709
- async close() {
1710
- await util.default.promisify(this._pool.end.bind(this._pool))();
1711
- }
1712
- };
1713
- //#endregion
1714
- //#region databases/postgres_db.ts
1715
- /**
1716
- * 2011 Peter 'Pita' Martischka
1717
- *
1718
- * Licensed under the Apache License, Version 2.0 (the "License");
1719
- * you may not use this file except in compliance with the License.
1720
- * You may obtain a copy of the License at
1721
- *
1722
- * http://www.apache.org/licenses/LICENSE-2.0
1723
- *
1724
- * Unless required by applicable law or agreed to in writing, software
1725
- * distributed under the License is distributed on an "AS-IS" BASIS,
1726
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1727
- * See the License for the specific language governing permissions and
1728
- * limitations under the License.
1729
- */
1730
- var postgres_db_default = class extends AbstractDatabase {
1731
- db;
1732
- upsertStatement;
1733
- constructor(settings) {
1734
- super(settings);
1735
- if (typeof settings === "string") settings = { connectionString: settings };
1736
- this.settings = settings;
1737
- this.settings.cache = settings.cache || 1e3;
1738
- this.settings.writeInterval = 100;
1739
- this.settings.json = true;
1740
- this.settings.max = this.settings.max || 20;
1741
- this.settings.min = this.settings.min || 4;
1742
- this.settings.idleTimeoutMillis = this.settings.idleTimeoutMillis || 1e3;
1743
- this.db = new pg.Pool(this.settings);
1744
- }
1745
- init(callback) {
1746
- const testTableExists = "SELECT 1 as exists FROM pg_tables WHERE tablename = 'store'";
1747
- const createTable = "CREATE TABLE IF NOT EXISTS store (\"key\" character varying(100) NOT NULL, \"value\" text NOT NULL, CONSTRAINT store_pkey PRIMARY KEY (key))";
1748
- this.upsertStatement = null;
1749
- const detectUpsertMethod = (callback) => {
1750
- const upsertViaFunction = "SELECT ueberdb_insert_or_update($1,$2)";
1751
- const upsertNatively = "INSERT INTO store(key, value) VALUES ($1, $2) ON CONFLICT (key) DO UPDATE SET value = excluded.value";
1752
- const createFunc = "CREATE OR REPLACE FUNCTION ueberdb_insert_or_update(character varying, text) RETURNS void AS $$ BEGIN IF EXISTS( SELECT * FROM store WHERE key = $1 ) THEN UPDATE store SET value = $2 WHERE key = $1; ELSE INSERT INTO store(key,value) VALUES( $1, $2 ); END IF; RETURN; END; $$ LANGUAGE plpgsql;";
1753
- const testNativeUpsert = `EXPLAIN ${upsertNatively}`;
1754
- this.db.query(testNativeUpsert, ["test-key", "test-value"], (err) => {
1755
- if (err) {
1756
- this.upsertStatement = upsertViaFunction;
1757
- this.db.query(createFunc, [], callback);
1758
- return;
1759
- }
1760
- this.upsertStatement = upsertNatively;
1761
- callback();
1762
- });
1763
- };
1764
- this.db.query(testTableExists, (err, result) => {
1765
- if (err != null) return callback(err);
1766
- if (result.rows.length === 0) this.db.query(createTable, (err) => {
1767
- if (err != null) return callback(err);
1768
- detectUpsertMethod(callback);
1769
- });
1770
- else detectUpsertMethod(callback);
1771
- });
1772
- }
1773
- get(key, callback) {
1774
- this.db.query("SELECT value FROM store WHERE key=$1", [key], (err, results) => {
1775
- let value = null;
1776
- if (!err && results.rows.length === 1) value = results.rows[0].value;
1777
- callback(err, value);
1778
- });
1779
- }
1780
- findKeys(key, notKey, callback) {
1781
- let query = "SELECT key FROM store WHERE key LIKE $1";
1782
- const params = [];
1783
- key = key.replace(/\*/g, "%");
1784
- params.push(key);
1785
- if (notKey != null) {
1786
- notKey = notKey.replace(/\*/g, "%");
1787
- query += " AND key NOT LIKE $2";
1788
- params.push(notKey);
1789
- }
1790
- this.db.query(query, params, (err, results) => {
1791
- const value = [];
1792
- if (!err && results.rows.length > 0) results.rows.forEach((val) => {
1793
- value.push(val.key);
1794
- });
1795
- callback(err, value);
1796
- });
1797
- }
1798
- set(key, value, callback) {
1799
- if (key.length > 100) callback(Error("Your Key can only be 100 chars"), "");
1800
- else if (this.upsertStatement != null) this.db.query(this.upsertStatement, [key, value], callback);
1801
- }
1802
- remove(key, callback) {
1803
- this.db.query("DELETE FROM store WHERE key=$1", [key], callback);
1804
- }
1805
- doBulk(bulk, callback) {
1806
- const replaceVALs = [];
1807
- let removeSQL = "DELETE FROM store WHERE key IN (";
1808
- const removeVALs = [];
1809
- let removeCount = 0;
1810
- for (const i in bulk) if (bulk[i].type === "set") replaceVALs.push([bulk[i].key, bulk[i].value]);
1811
- else if (bulk[i].type === "remove") {
1812
- if (removeCount !== 0) removeSQL += ",";
1813
- removeCount += 1;
1814
- removeSQL += `$${removeCount}`;
1815
- removeVALs.push(bulk[i].key);
1816
- }
1817
- removeSQL += ");";
1818
- if (!this.upsertStatement) return;
1819
- const functions = replaceVALs.map((v) => (cb) => this.db.query(this.upsertStatement, v, cb));
1820
- const removeFunction = (callback) => {
1821
- if (!(removeVALs.length < 1)) this.db.query(removeSQL, removeVALs, callback);
1822
- else callback();
1823
- };
1824
- functions.push(removeFunction);
1825
- async.default.parallel(functions, callback);
1826
- }
1827
- close(callback) {
1828
- this.db.end(callback);
1829
- }
1830
- };
1831
- //#endregion
1832
- //#region databases/postgrespool_db.ts
1833
- var PostgresDB = class extends postgres_db_default {
1834
- constructor(settings) {
1835
- console.warn("ueberdb: The postgrespool database driver is deprecated and will be removed in a future version. Use postgres instead.");
1836
- super(settings);
1837
- }
1838
- };
1839
- //#endregion
1840
- //#region databases/redis_db.ts
1841
- /**
1842
- * 2011 Peter 'Pita' Martischka
1843
- *
1844
- * Licensed under the Apache License, Version 2.0 (the "License");
1845
- * you may not use this file except in compliance with the License.
1846
- * You may obtain a copy of the License at
1847
- *
1848
- * http://www.apache.org/licenses/LICENSE-2.0
1849
- *
1850
- * Unless required by applicable law or agreed to in writing, software
1851
- * distributed under the License is distributed on an "AS-IS" BASIS,
1852
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1853
- * See the License for the specific language governing permissions and
1854
- * limitations under the License.
1855
- */
1856
- var RedisDB = class extends AbstractDatabase {
1857
- _client;
1858
- constructor(settings) {
1859
- super(settings);
1860
- this._client = null;
1861
- this.settings = settings || {};
1862
- }
1863
- get isAsync() {
1864
- return true;
1865
- }
1866
- async init() {
1867
- if (this.settings.url) this._client = (0, redis.createClient)({ url: this.settings.url });
1868
- else if (this.settings.host) {
1869
- const options = { socket: {
1870
- host: this.settings.host,
1871
- port: Number(this.settings.port)
1872
- } };
1873
- if (this.settings.password) options.password = this.settings.password;
1874
- if (this.settings.user) options.username = this.settings.user;
1875
- this._client = (0, redis.createClient)(options);
1876
- }
1877
- if (this._client) {
1878
- await this._client.connect();
1879
- await this._client.ping();
1880
- }
1881
- }
1882
- async get(key) {
1883
- if (this._client == null) return null;
1884
- return await this._client.get(key);
1885
- }
1886
- async findKeys(key, notKey) {
1887
- if (this._client == null) return null;
1888
- const [_, type] = /^([^:*]+):\*$/.exec(key) || [];
1889
- if (type != null && ["*:*:*", `${key}:*`].includes(notKey)) return await this._client.sMembers(`ueberDB:keys:${type}`);
1890
- let keys = await this._client.keys(key.replace(/[?[\]\\]/g, "\\$&"));
1891
- if (notKey != null) {
1892
- const regex = this.createFindRegex(key, notKey);
1893
- keys = keys.filter((k) => regex.test(k));
1894
- }
1895
- return keys;
1896
- }
1897
- async set(key, value) {
1898
- if (this._client == null) return null;
1899
- const matches = /^([^:]+):([^:]+)$/.exec(key);
1900
- await Promise.all([matches && this._client.sAdd(`ueberDB:keys:${matches[1]}`, matches[0]), this._client.set(key, value)]);
1901
- }
1902
- async remove(key) {
1903
- if (this._client == null) return null;
1904
- const matches = /^([^:]+):([^:]+)$/.exec(key);
1905
- await Promise.all([matches && this._client.sRem(`ueberDB:keys:${matches[1]}`, matches[0]), this._client.del(key)]);
1906
- }
1907
- async doBulk(bulk) {
1908
- if (this._client == null) return null;
1909
- const multi = this._client.multi();
1910
- for (const { key, type, value } of bulk) {
1911
- const matches = /^([^:]+):([^:]+)$/.exec(key);
1912
- if (type === "set") {
1913
- if (matches) multi.sAdd(`ueberDB:keys:${matches[1]}`, matches[0]);
1914
- multi.set(key, value);
1915
- } else if (type === "remove") {
1916
- if (matches) multi.sRem(`ueberDB:keys:${matches[1]}`, matches[0]);
1917
- multi.del(key);
1918
- }
1919
- }
1920
- await multi.exec();
1921
- }
1922
- async close() {
1923
- if (this._client == null) return null;
1924
- await this._client.quit();
1925
- this._client = null;
1926
- }
1927
- };
1928
- //#endregion
1929
- //#region databases/rethink_db.ts
1930
- /**
1931
- * 2016 Remi Arnaud
1932
- *
1933
- * Licensed under the Apache License, Version 2.0 (the "License");
1934
- * you may not use this file except in compliance with the License.
1935
- * You may obtain a copy of the License at
1936
- *
1937
- * http://www.apache.org/licenses/LICENSE-2.0
1938
- *
1939
- * Unless required by applicable law or agreed to in writing, software
1940
- * distributed under the License is distributed on an "AS-IS" BASIS,
1941
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1942
- * See the License for the specific language governing permissions and
1943
- * limitations under the License.
1944
- */
1945
- var Rethink_db = class extends AbstractDatabase {
1946
- host;
1947
- db;
1948
- port;
1949
- table;
1950
- connection;
1951
- constructor(settings) {
1952
- super(settings);
1953
- if (!settings) settings = {};
1954
- if (!settings.host) settings.host = "localhost";
1955
- if (!settings.port) settings.port = 28015;
1956
- if (!settings.db) settings.db = "test";
1957
- if (!settings.table) settings.table = "test";
1958
- this.host = settings.host;
1959
- this.db = settings.db;
1960
- this.port = settings.port;
1961
- this.table = settings.table;
1962
- this.connection = null;
1963
- }
1964
- init(callback) {
1965
- rethinkdb.default.connect(this, (err, conn) => {
1966
- if (err) throw err;
1967
- this.connection = conn;
1968
- rethinkdb.default.table(this.table).run(this.connection, (err, cursor) => {
1969
- if (err) rethinkdb.default.tableCreate(this.table).run(this.connection, callback);
1970
- else if (callback) callback(null, cursor);
1971
- });
1972
- });
1973
- }
1974
- get(key, callback) {
1975
- rethinkdb.default.table(this.table).get(key).run(this.connection, (err, item) => {
1976
- callback(err, item ? item.content : item);
1977
- });
1978
- }
1979
- findKeys(key, notKey, callback) {
1980
- const keys = [];
1981
- const regex = this.createFindRegex(key, notKey);
1982
- rethinkdb.default.filter((item) => {
1983
- if (item.id.search(regex) !== -1) keys.push(item.id);
1984
- }).run(this.connection, callback);
1985
- }
1986
- set(key, value, callback) {
1987
- rethinkdb.default.table(this.table).insert({
1988
- id: key,
1989
- content: value
1990
- }, { conflict: "replace" }).run(this.connection, callback);
1991
- }
1992
- doBulk(bulk, callback) {
1993
- const _in = [];
1994
- const _out = [];
1995
- for (const i in bulk) if (bulk[i].type === "set") _in.push({
1996
- id: bulk[i].key,
1997
- content: bulk[i].value
1998
- });
1999
- else if (bulk[i].type === "remove") _out.push(bulk[i].key);
2000
- async.default.parallel([(cb) => {
2001
- rethinkdb.default.table(this.table).insert(_in, { conflict: "replace" }).run(this.connection, cb);
2002
- }, (cb) => {
2003
- rethinkdb.default.table(this.table).getAll(_out).delete().run(this.connection, cb);
2004
- }], callback);
2005
- }
2006
- remove(key, callback) {
2007
- rethinkdb.default.table(this.table).get(key).delete().run(this.connection, callback);
2008
- }
2009
- close(callback) {
2010
- if (this.connection) this.connection.close(callback);
2011
- }
2012
- };
2013
- //#endregion
2014
- //#region databases/sqlite_db.ts
2015
- /**
2016
- * 2011 Peter 'Pita' Martischka
2017
- *
2018
- * Licensed under the Apache License, Version 2.0 (the "License");
2019
- * you may not use this file except in compliance with the License.
2020
- * You may obtain a copy of the License at
2021
- *
2022
- * http://www.apache.org/licenses/LICENSE-2.0
2023
- *
2024
- * Unless required by applicable law or agreed to in writing, software
2025
- * distributed under the License is distributed on an "AS-IS" BASIS,
2026
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
2027
- * See the License for the specific language governing permissions and
2028
- * limitations under the License.
2029
- */
2030
- var SQLiteDB = class extends AbstractDatabase {
2031
- db;
2032
- constructor(settings) {
2033
- super(settings);
2034
- this.db = null;
2035
- if (!settings || !settings.filename) settings = { filename: ":memory:" };
2036
- this.settings = settings;
2037
- if (settings.filename === ":memory:") {
2038
- this.settings.cache = 0;
2039
- this.settings.writeInterval = 0;
2040
- this.settings.json = true;
2041
- } else {
2042
- this.settings.cache = 1e3;
2043
- this.settings.writeInterval = 100;
2044
- this.settings.json = true;
2045
- }
2046
- }
2047
- init(callback) {
2048
- this.db = new rusty_store_kv.SQLite(this.settings.filename);
2049
- callback();
2050
- }
2051
- get(key, callback) {
2052
- const res = this.db.get(key);
2053
- callback(null, res ? res : null);
2054
- }
2055
- findKeys(key, notKey, callback) {
2056
- const res = this.db?.findKeys(key, notKey);
2057
- callback(null, res);
2058
- }
2059
- set(key, value, callback) {
2060
- const res = this.db.set(key, value);
2061
- res ? callback(null, null) : callback(null, res);
2062
- }
2063
- remove(key, callback) {
2064
- this.db.remove(key);
2065
- callback(null, null);
2066
- }
2067
- doBulk(bulk, callback) {
2068
- const convertedBulk = bulk.map((b) => {
2069
- if (b.value === null) return {
2070
- key: b.key,
2071
- type: b.type
2072
- };
2073
- else return b;
2074
- });
2075
- this.db.doBulk(convertedBulk);
2076
- callback();
2077
- }
2078
- close(callback) {
2079
- callback();
2080
- this.db.close();
2081
- }
2082
- };
2083
- //#endregion
2084
- //#region databases/surrealdb_db.ts
2085
- /**
2086
- * 2023 Samuel Schwanzer
2087
- *
2088
- * Licensed under the Apache License, Version 2.0 (the "License");
2089
- * you may not use this file except in compliance with the License.
2090
- * You may obtain a copy of the License at
2091
- *
2092
- * http://www.apache.org/licenses/LICENSE-2.0
2093
- *
2094
- * Unless required by applicable law or agreed to in writing, software
2095
- * distributed under the License is distributed on an "AS-IS" BASIS,
2096
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
2097
- * See the License for the specific language governing permissions and
2098
- * limitations under the License.
2099
- */
2100
- const DATABASE = "ueberdb";
2101
- const WILDCARD = "*";
2102
- const replaceAt = function(index, replacement, original) {
2103
- return original.substring(0, index) + replacement + original.substring(index + replacement.length);
2104
- };
2105
- const escapeKey = (key) => {
2106
- const index = key.indexOf(":");
2107
- if (index > -1) return replaceAt(index, "_", key);
2108
- return key;
2109
- };
2110
- const unescapeKey = (key, originalKey) => {
2111
- const index = originalKey.indexOf(":");
2112
- if (index > -1) return replaceAt(index, ":", key);
2113
- return key;
2114
- };
2115
- var SurrealDB = class extends AbstractDatabase {
2116
- _client;
2117
- constructor(settings) {
2118
- super(settings);
2119
- this._client = null;
2120
- }
2121
- get isAsync() {
2122
- return true;
2123
- }
2124
- async init() {
2125
- if (this.settings.url) {
2126
- this._client = new surrealdb.Surreal();
2127
- await this._client.connect(this.settings.url);
2128
- } else if (this.settings.host) {
2129
- const port = this.settings.port || 8e3;
2130
- const protocol = this.settings.clientOptions?.protocol || "http://";
2131
- const path = this.settings.clientOptions?.path || "/rpc";
2132
- const host = this.settings.host;
2133
- this._client = new surrealdb.Surreal();
2134
- await this._client.connect(`${protocol}${host}:${port}${path}`);
2135
- }
2136
- if (this.settings.user && this.settings.password) await this._client.signin({
2137
- username: this.settings.user,
2138
- password: this.settings.password
2139
- });
2140
- await this._client.use({
2141
- namespace: DATABASE,
2142
- database: DATABASE
2143
- });
2144
- }
2145
- async get(key) {
2146
- if (this._client == null) return null;
2147
- key = escapeKey(key);
2148
- const rows = (await this._client.query("SELECT key, value FROM store WHERE key = $key", { key }))[0] || [];
2149
- if (rows.length === 0) return null;
2150
- const row = rows[0];
2151
- if (typeof row === "string") return row;
2152
- return unescapeKey(row.value, key);
2153
- }
2154
- async findKeys(key, notKey) {
2155
- if (this._client == null) return null;
2156
- const queryString = notKey != null ? `SELECT key FROM store WHERE ${this.transformWildcard(key, "key")} AND ${this.transformWildcardNegative(notKey, "notKey")}` : `SELECT key FROM store WHERE ${this.transformWildcard(key, "key")}`;
2157
- const cleanKey = key.replace(WILDCARD, "");
2158
- const cleanNotKey = (notKey || "").replace(WILDCARD, "");
2159
- const bindings = { key: cleanKey };
2160
- if (notKey != null) bindings.notKey = cleanNotKey;
2161
- const res = await this._client.query(queryString, bindings);
2162
- return this.transformResult(res[0] || [], cleanKey);
2163
- }
2164
- transformWildcard(key, keyExpr) {
2165
- if (key.startsWith(WILDCARD) && key.endsWith(WILDCARD)) return `${keyExpr} CONTAINS $${keyExpr}`;
2166
- else if (key.startsWith(WILDCARD)) return `string::ends_with(${keyExpr}, $${keyExpr})`;
2167
- else if (key.endsWith(WILDCARD)) return `string::starts_with(${keyExpr}, $${keyExpr})`;
2168
- else return `${keyExpr} = $${keyExpr}`;
2169
- }
2170
- transformWildcardNegative(key, keyExpr) {
2171
- if (key.startsWith(WILDCARD) && key.endsWith(WILDCARD)) return `key CONTAINSNOT $${keyExpr}`;
2172
- else if (key.startsWith(WILDCARD)) return `string::ends_with(key, $${keyExpr}) == false`;
2173
- else if (key.endsWith(WILDCARD)) return `string::starts_with(key, $${keyExpr}) == false`;
2174
- else return `key != $${keyExpr}`;
2175
- }
2176
- transformResult(rows, originalKey) {
2177
- const value = [];
2178
- if (typeof rows === "string") {
2179
- value.push(unescapeKey(rows, originalKey));
2180
- return value;
2181
- }
2182
- for (const row of rows) value.push(unescapeKey(row.key, originalKey));
2183
- return value;
2184
- }
2185
- async set(key, value) {
2186
- if (this._client == null) return null;
2187
- const exists = await this.get(key);
2188
- const escapedKey = escapeKey(key);
2189
- if (exists) await this._client.query("UPDATE store SET value = $value WHERE key = $key", {
2190
- key: escapedKey,
2191
- value
2192
- });
2193
- else await this._client.query("INSERT INTO store (key, value) VALUES ($key, $value)", {
2194
- key: escapedKey,
2195
- value
2196
- });
2197
- }
2198
- async remove(key) {
2199
- if (this._client == null) return null;
2200
- key = escapeKey(key);
2201
- return await this._client.query("DELETE FROM store WHERE key = $key", { key });
2202
- }
2203
- async doBulk(bulk) {
2204
- if (this._client == null) return null;
2205
- for (const b of bulk) if (b.type === "set") await this.set(b.key, b.value);
2206
- else if (b.type === "remove") await this.remove(b.key);
2207
- }
2208
- async close() {
2209
- if (this._client == null) return null;
2210
- await this._client.close();
2211
- this._client = null;
2212
- }
2213
- };
2214
- //#endregion
2215
- //#region databases/rusty_db.ts
2216
- var Rusty_db = class extends AbstractDatabase {
2217
- db;
2218
- constructor(settings) {
2219
- super(settings);
2220
- this.settings.cache = 0;
2221
- this.settings.writeInterval = 0;
2222
- this.settings.json = false;
2223
- }
2224
- get isAsync() {
2225
- return true;
2226
- }
2227
- findKeys(key, notKey) {
2228
- return this.db.findKeys(key, notKey);
2229
- }
2230
- get(key) {
2231
- const val = this.db.get(key);
2232
- if (!val) return val;
2233
- try {
2234
- return JSON.parse(val);
2235
- } catch (e) {
2236
- return val;
2237
- }
2238
- }
2239
- async init() {
2240
- this.db = new rusty_store_kv.KeyValueDB(this.settings.filename);
2241
- }
2242
- close() {
2243
- this.db?.close();
2244
- this.db = null;
2245
- }
2246
- remove(key) {
2247
- this.db.remove(key);
2248
- }
2249
- set(key, value) {
2250
- if (typeof value === "object") {
2251
- const valStr = JSON.stringify(value);
2252
- this.db.set(key, valStr);
2253
- } else this.db.set(key, value.toString());
2254
- }
2255
- destroy() {
2256
- this.db.destroy();
2257
- }
2258
- };
2259
- //#endregion
6
+ require("./_virtual/_rolldown/runtime.js");
7
+ const require_CacheAndBufferLayer = require("./lib/CacheAndBufferLayer.js");
8
+ const require_logging = require("./lib/logging.js");
9
+ let util = require("util");
2260
10
  //#region index.ts
2261
11
  /**
2262
12
  * 2011 Peter 'Pita' Martischka
@@ -2295,7 +45,7 @@ for (const fn of [
2295
45
  "remove",
2296
46
  "set",
2297
47
  "setSub"
2298
- ]) if (fn in cbDb) cbDb[fn] = (0, util.callbackify)(Database$1.prototype[fn]);
48
+ ]) if (fn in cbDb) cbDb[fn] = (0, util.callbackify)(require_CacheAndBufferLayer.Database.prototype[fn]);
2299
49
  const makeDoneCallback = (callback, deprecated) => (err) => {
2300
50
  if (callback) callback(err);
2301
51
  if (deprecated) deprecated(err);
@@ -2326,38 +76,40 @@ var Database = class {
2326
76
  this.type = type;
2327
77
  this.dbSettings = dbSettings;
2328
78
  this.wrapperSettings = wrapperSettings;
2329
- this.logger = normalizeLogger(logger);
79
+ this.logger = require_logging.normalizeLogger(logger);
2330
80
  }
2331
81
  /**
2332
82
  * @param callback - Deprecated. Node-style callback. If null, a Promise is returned.
2333
83
  */
2334
84
  init(callback = null) {
2335
- const db = this.initDB();
2336
- db.logger = this.logger;
2337
- this.db = new Database$1(db, this.wrapperSettings, this.logger);
2338
- this.metrics = this.db.metrics;
2339
- if (callback != null) return cbDb.init.call(this.db);
2340
- return this.db.init();
85
+ const p = this.initDB().then((db) => {
86
+ db.logger = this.logger;
87
+ this.db = new require_CacheAndBufferLayer.Database(db, this.wrapperSettings, this.logger);
88
+ this.metrics = this.db.metrics;
89
+ return this.db.init();
90
+ });
91
+ if (callback != null) return cbDb.init.call({ init: () => p });
92
+ return p;
2341
93
  }
2342
- initDB() {
94
+ async initDB() {
2343
95
  switch (this.type) {
2344
- case "mysql": return new mysql_db_default(this.dbSettings);
2345
- case "postgres": return new postgres_db_default(this.dbSettings);
2346
- case "sqlite": return new SQLiteDB(this.dbSettings);
2347
- case "rustydb": return new Rusty_db(this.dbSettings);
2348
- case "mongodb": return new mongodb_db_default(this.dbSettings);
2349
- case "redis": return new RedisDB(this.dbSettings);
2350
- case "cassandra": return new Cassandra_db(this.dbSettings);
2351
- case "dirty": return new dirty_db_default(this.dbSettings);
2352
- case "dirtygit": return new dirty_git_db_default(this.dbSettings);
2353
- case "elasticsearch": return new elasticsearch_db_default(this.dbSettings);
2354
- case "memory": return new MemoryDB(this.dbSettings);
2355
- case "mock": return new mock_db_default(this.dbSettings);
2356
- case "mssql": return new MSSQL(this.dbSettings);
2357
- case "postgrespool": return new PostgresDB(this.dbSettings);
2358
- case "rethink": return new Rethink_db(this.dbSettings);
2359
- case "couch": return new Couch_db(this.dbSettings);
2360
- case "surrealdb": return new SurrealDB(this.dbSettings);
96
+ case "mysql": return new (await (Promise.resolve().then(() => require("./databases/mysql_db.js")))).default(this.dbSettings);
97
+ case "postgres": return new (await (Promise.resolve().then(() => require("./databases/postgres_db.js")))).default(this.dbSettings);
98
+ case "sqlite": return new (await (Promise.resolve().then(() => require("./databases/sqlite_db.js")))).default(this.dbSettings);
99
+ case "rustydb": return new (await (Promise.resolve().then(() => require("./databases/rusty_db.js")))).default(this.dbSettings);
100
+ case "mongodb": return new (await (Promise.resolve().then(() => require("./databases/mongodb_db.js")))).default(this.dbSettings);
101
+ case "redis": return new (await (Promise.resolve().then(() => require("./databases/redis_db.js")))).default(this.dbSettings);
102
+ case "cassandra": return new (await (Promise.resolve().then(() => require("./databases/cassandra_db.js")))).default(this.dbSettings);
103
+ case "dirty": return new (await (Promise.resolve().then(() => require("./databases/dirty_db.js")))).default(this.dbSettings);
104
+ case "dirtygit": return new (await (Promise.resolve().then(() => require("./databases/dirty_git_db.js")))).default(this.dbSettings);
105
+ case "elasticsearch": return new (await (Promise.resolve().then(() => require("./databases/elasticsearch_db.js")))).default(this.dbSettings);
106
+ case "memory": return new (await (Promise.resolve().then(() => require("./databases/memory_db.js")))).default(this.dbSettings);
107
+ case "mock": return new (await (Promise.resolve().then(() => require("./databases/mock_db.js")))).default(this.dbSettings);
108
+ case "mssql": return new (await (Promise.resolve().then(() => require("./databases/mssql_db.js")))).default(this.dbSettings);
109
+ case "postgrespool": return new (await (Promise.resolve().then(() => require("./databases/postgrespool_db.js")))).default(this.dbSettings);
110
+ case "rethink": return new (await (Promise.resolve().then(() => require("./databases/rethink_db.js")))).default(this.dbSettings);
111
+ case "couch": return new (await (Promise.resolve().then(() => require("./databases/couch_db.js")))).default(this.dbSettings);
112
+ case "surrealdb": return new (await (Promise.resolve().then(() => require("./databases/surrealdb_db.js")))).default(this.dbSettings);
2361
113
  default: throw new Error("Invalid database type");
2362
114
  }
2363
115
  }