@leyyo/cache
Version:
Common cache library
445 lines (444 loc) • 18.3 kB
JavaScript
"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.CacheHashAbstract = void 0;
const util_1 = require("../util");
const config_1 = require("../config");
// noinspection DuplicatedCode,JSUnusedGlobalSymbols
class CacheHashAbstract {
// endregion properties
// region constructor
constructor(channel) {
this.channel = channel;
util_1.cacheUtil.bindAll(this);
}
// endregion constructor
// region private
_formatRawValue(field, value, throwable = true) {
switch (typeof value) {
case "string":
const str = value.trim();
if (str) {
return str;
}
if (throwable) {
throw new Error(`Empty value for field[${field}]`);
}
return null;
case "number":
case "bigint":
return String(value);
case "boolean":
return value ? 'true' : 'false';
default:
if (!value) {
if (throwable) {
throw new Error(`Empty value for field[${field}]`);
}
return null;
}
if (throwable) {
throw new Error(`Invalid field[${field}] value, type of value: ${typeof value}`);
}
return null;
}
}
_formatRawValues(record, throwable = true) {
const errors = [];
const result = {};
for (const [field, value] of Object.entries(record)) {
switch (typeof value) {
case "string":
const str = value.trim();
if (str) {
result[field] = str;
}
else if (throwable) {
errors.push(`Empty value for field[${field}]`);
}
break;
case "number":
case "bigint":
result[field] = String(value);
break;
case "boolean":
result[field] = value ? 'true' : 'false';
break;
default:
if (!value) {
if (throwable) {
errors.push(`Empty value for field[${field}]`);
}
}
else if (throwable) {
errors.push(`Invalid field[${field}] value, type of value: ${typeof value}`);
}
break;
}
}
if (Object.keys(result).length < 1 && throwable) {
errors.push(`Empty value set`);
}
if (errors.length > 0) {
throw new Error(errors.join(', '));
}
return result;
}
// endregion private
// region delete
delete(key, fields) {
return __awaiter(this, void 0, void 0, function* () {
if (!this.prop.enabled) {
return this.invalidator.disabledNumber(config_1.CACHE_DISABLED);
}
const { full } = this.format.key(key);
if (!full) {
return this.invalidator.ignoreNumber(config_1.CACHE_EMPTY_KEY, 'Empty key');
}
const items = this.format.fields(fields);
if (items.length < 1) {
return this.invalidator.ignoreNumber(config_1.CACHE_EMPTY_VALUE, 'Empty fields');
}
return this.invalidator.success(yield this.$delete(full, items), [full]);
});
}
// endregion delete
// region members
exists(key, field) {
return __awaiter(this, void 0, void 0, function* () {
if (!this.prop.enabled) {
return this.invalidator.disabledNumber(config_1.CACHE_DISABLED);
}
const { full } = this.format.key(key);
if (!full) {
return this.invalidator.ignoreNumber(config_1.CACHE_EMPTY_KEY, 'Empty key');
}
const item = this.format.field(field);
if (!item) {
return this.invalidator.ignoreNumber(config_1.CACHE_EMPTY_VALUE, 'Empty field');
}
return this.invalidator.success((yield this.$exists(full, item)) ? 1 : 0, [full]);
});
}
existMore(key, fields) {
return __awaiter(this, void 0, void 0, function* () {
if (!this.prop.enabled) {
return this.invalidator.disabledArray();
}
const { full } = this.format.key(key);
if (!full) {
return this.invalidator.ignoreArray('Empty key');
}
const items = this.format.fields(fields);
if (items.length < 1) {
return this.invalidator.ignoreArray('Empty fields');
}
return this.invalidator.success((yield Promise.all(items.map(item => this.$exists(full, item)))).map(i => i ? 1 : 0), [full]);
});
}
getLength(key) {
return __awaiter(this, void 0, void 0, function* () {
if (!this.prop.enabled) {
return this.invalidator.disabledNumber(config_1.CACHE_DISABLED);
}
const { full } = this.format.key(key);
if (!full) {
return this.invalidator.ignoreNumber(config_1.CACHE_EMPTY_KEY, 'Empty key');
}
return this.invalidator.success(yield this.$length(full), [full]);
});
}
listFields(key) {
return __awaiter(this, void 0, void 0, function* () {
if (!this.prop.enabled) {
return this.invalidator.disabledArray();
}
const { full } = this.format.key(key);
if (!full) {
return this.invalidator.ignoreArray('Empty key');
}
return this.invalidator.success(yield this.$fields(full), [full]);
});
}
// endregion members
// region get
getAll(key) {
return __awaiter(this, void 0, void 0, function* () {
if (!this.prop.enabled) {
return this.invalidator.disabledNull();
}
const { full } = this.format.key(key);
if (!full) {
return this.invalidator.ignoreNull('Empty key');
}
return this.invalidator.success(yield this.$getAll(full), [full]);
});
}
getMore(key, fields) {
return __awaiter(this, void 0, void 0, function* () {
if (!this.prop.enabled) {
return this.invalidator.disabledNull();
}
const { full } = this.format.key(key);
if (!full) {
return this.invalidator.ignoreNull('Empty key');
}
const items = this.format.fields(fields);
if (items.length < 1) {
return this.invalidator.ignoreNull('Empty fields');
}
const values = yield this.$get(full, items);
return this.invalidator.success(util_1.cacheUtil.objectFromKeys(items, null, values), [full]);
});
}
getValue(key, field) {
return __awaiter(this, void 0, void 0, function* () {
if (!this.prop.enabled) {
return this.invalidator.disabledText();
}
const { full } = this.format.key(key);
if (!full) {
return this.invalidator.ignoreText('Empty key');
}
const checkedField = this.format.field(field);
if (!checkedField) {
return this.invalidator.ignoreText('Empty field');
}
return this.invalidator.success(yield this.$getOne(full, checkedField), [full]);
});
}
// endregion get
// region set
setValue(key, field, value) {
return __awaiter(this, void 0, void 0, function* () {
if (!this.prop.enabled) {
return this.invalidator.disabledNumber(config_1.CACHE_DISABLED);
}
const { full } = this.format.key(key);
if (!full) {
return this.invalidator.ignoreNumber(config_1.CACHE_EMPTY_KEY, 'Empty key');
}
const checkField = this.format.field(field);
if (!checkField) {
return this.invalidator.ignoreNumber(config_1.CACHE_EMPTY_VALUE, 'Empty field');
}
const str = this._formatRawValue(checkField, value, true);
return this.invalidator.success(yield this.$set(full, { [checkField]: str }), [full]);
});
}
setValuesMore(key, doc) {
return __awaiter(this, void 0, void 0, function* () {
if (!this.prop.enabled) {
return this.invalidator.disabledNumber(config_1.CACHE_DISABLED);
}
const { full } = this.format.key(key);
if (!full) {
return this.invalidator.ignoreNumber(config_1.CACHE_EMPTY_KEY, 'Empty key');
}
if (!doc) {
return this.invalidator.ignoreNumber(config_1.CACHE_EMPTY_VALUE, 'Empty values');
}
if (typeof doc !== 'object') {
throw new Error('Invalid set data');
}
const tempValue = {};
// Array<Partial<A>> | Array<[KeyId, Partial<A>]>
if (Array.isArray(doc)) {
if (doc.length < 1) {
return this.invalidator.ignoreNumber(config_1.CACHE_EMPTY_VALUE, 'Empty array items');
}
const first = doc[0];
// FieldTupleArray<A>
if (Array.isArray(first) && first.length === 2) {
const arr = doc;
arr.forEach(item => {
const [key, value] = item;
tempValue[key] = value;
});
}
// normal array
else {
return this.invalidator.ignoreNumber(config_1.CACHE_EMPTY_VALUE, 'Invalid array tuples');
}
}
// FieldMap<A>
else if (doc instanceof Map) {
if (doc.size < 1) {
return this.invalidator.ignoreNumber(config_1.CACHE_EMPTY_VALUE, 'Empty map items');
}
for (const [key, value] of doc.entries()) {
tempValue[key] = value;
}
}
// Partial<A>
else {
if (Object.keys(doc).length < 1) {
return this.invalidator.ignoreNumber(config_1.CACHE_EMPTY_KEY, 'Empty record value');
}
for (const [key, value] of Object.entries(doc)) {
tempValue[key] = value;
}
}
const formatted = this._formatRawValues(tempValue, true);
if (Object.keys(formatted).length < 1) {
return this.invalidator.ignoreNumber(config_1.CACHE_EMPTY_KEY, 'Empty record value');
}
return this.invalidator.success(yield this.$set(full, formatted), [full]);
});
}
// endregion set
// region expiry
getTimestamp(key, fields, opt) {
return __awaiter(this, void 0, void 0, function* () {
if (!this.prop.enabled) {
return this.invalidator.disabledRecord();
}
const { full } = this.format.key(key);
if (!full) {
return this.invalidator.ignoreRecord('Empty key');
}
const items = this.format.fields(fields);
if (items.length < 1) {
return this.invalidator.ignoreRecord('Empty fields');
}
const times = yield this.$getTimestamp(full, items);
if (times.length < 1) {
return this.invalidator.success({}, [full]);
}
const unit = this.check.$expiryUnit(opt === null || opt === void 0 ? void 0 : opt.unit);
switch (unit) {
case "milliseconds":
return this.invalidator.success(util_1.cacheUtil.objectFromKeys(items, 0, times), [full]);
case 'seconds':
return this.invalidator.success(util_1.cacheUtil.objectFromKeys(times.map(time => time / 1000), 0, times), [full]);
case 'minutes':
return this.invalidator.success(util_1.cacheUtil.objectFromKeys(times.map(time => time / 60000), 0, times), [full]);
default:
return this.invalidator.success(util_1.cacheUtil.objectFromKeys(items, 0, times), [full]);
}
});
}
getTtl(key, fields, opt) {
return __awaiter(this, void 0, void 0, function* () {
if (!this.prop.enabled) {
return this.invalidator.disabledRecord();
}
const { full } = this.format.key(key);
if (!full) {
return this.invalidator.ignoreRecord('Empty key');
}
const items = this.format.fields(fields);
if (items.length < 1) {
return this.invalidator.ignoreRecord('Empty fields');
}
const times = yield this.$getTtl(full, items);
if (times.length < 1) {
return this.invalidator.success({}, [full]);
}
const unit = this.check.$expiryUnit(opt === null || opt === void 0 ? void 0 : opt.unit);
switch (unit) {
case "milliseconds":
return this.invalidator.success(util_1.cacheUtil.objectFromKeys(items, 0, times), [full]);
case 'seconds':
return this.invalidator.success(util_1.cacheUtil.objectFromKeys(times.map(time => time / 1000), 0, times), [full]);
case 'minutes':
return this.invalidator.success(util_1.cacheUtil.objectFromKeys(times.map(time => time / 60000), 0, times), [full]);
default:
return this.invalidator.success(util_1.cacheUtil.objectFromKeys(items, 0, times), [full]);
}
});
}
setTimestamp(key, fields, opt) {
return __awaiter(this, void 0, void 0, function* () {
if (!this.prop.enabled) {
return this.invalidator.disabledRecord();
}
const { full } = this.format.key(key);
if (!full) {
return this.invalidator.ignoreRecord('Empty key');
}
const items = this.format.fields(fields);
if (items.length < 1) {
return this.invalidator.ignoreRecord('Empty fields');
}
if (!opt) {
opt = {};
}
const milliseconds = this.check.$timestamp(opt.expiry);
if (milliseconds < 1) {
return this.invalidator.ignoreRecord('Invalid time value');
}
const mode = this.check.$expiryMode(opt.mode);
const result = yield this.$setTimestamp(full, items, milliseconds, mode);
return this.invalidator.success(util_1.cacheUtil.objectFromKeys(result, -1, result), [full]);
});
}
setTtl(key, fields, opt) {
return __awaiter(this, void 0, void 0, function* () {
if (!this.prop.enabled) {
return this.invalidator.disabledRecord();
}
const { full } = this.format.key(key);
if (!full) {
return this.invalidator.ignoreRecord('Empty key');
}
const items = this.format.fields(fields);
if (items.length < 1) {
return this.invalidator.ignoreRecord('Empty fields');
}
if (!opt) {
opt = {};
}
const milliseconds = this.check.$timestamp(opt.expiry);
if (milliseconds < 1) {
return this.invalidator.ignoreRecord('Invalid time value');
}
const mode = this.check.$expiryMode(opt.mode);
const result = yield this.$setTtl(full, items, milliseconds, mode);
return this.invalidator.success(util_1.cacheUtil.objectFromKeys(result, -1, result), [full]);
});
}
persist(key, fields) {
return __awaiter(this, void 0, void 0, function* () {
if (!this.prop.enabled) {
return this.invalidator.disabledRecord();
}
const { full } = this.format.key(key);
if (!full) {
return this.invalidator.ignoreRecord('Empty key');
}
const items = this.format.fields(fields);
if (items.length < 1) {
return this.invalidator.ignoreRecord('Empty fields');
}
const result = yield this.$persist(full, items);
return this.invalidator.success(util_1.cacheUtil.objectFromKeys(items, -2, result), [full]);
});
}
// endregion expiry
// region secure
get $flat() {
return this;
}
get $secure() {
return this;
}
get $back() {
return this;
}
$init() {
this.format = this.channel.format;
this.invalidator = this.channel.invalidator;
this.prop = this.channel.prop;
this.check = this.channel.prop.$secure;
}
}
exports.CacheHashAbstract = CacheHashAbstract;