@feathersjs/memory
Version:
An in memory service store
211 lines • 7.79 kB
JavaScript
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.MemoryService = exports.MemoryAdapter = void 0;
exports.memory = memory;
const errors_1 = require("@feathersjs/errors");
const commons_1 = require("@feathersjs/commons");
const adapter_commons_1 = require("@feathersjs/adapter-commons");
const sift_1 = __importDefault(require("sift"));
const _select = (data, params, ...args) => {
const base = (0, adapter_commons_1.select)(params, ...args);
return base(JSON.parse(JSON.stringify(data)));
};
class MemoryAdapter extends adapter_commons_1.AdapterBase {
constructor(options = {}) {
super({
id: 'id',
matcher: sift_1.default,
sorter: adapter_commons_1.sorter,
store: {},
startId: 0,
...options
});
this._uId = this.options.startId;
this.store = { ...this.options.store };
}
async getEntries(_params) {
const params = _params || {};
return this._find({
...params,
paginate: false
});
}
getQuery(params) {
const { $skip, $sort, $limit, $select, ...query } = params.query || {};
return {
query,
filters: { $skip, $sort, $limit, $select }
};
}
async _find(params = {}) {
const { paginate } = this.getOptions(params);
const { query, filters } = this.getQuery(params);
let values = commons_1._.values(this.store);
const hasSkip = filters.$skip !== undefined;
const hasSort = filters.$sort !== undefined;
const hasLimit = filters.$limit !== undefined;
const hasQuery = commons_1._.keys(query).length > 0;
if (hasSort) {
values.sort(this.options.sorter(filters.$sort));
}
if (paginate) {
if (hasQuery) {
values = values.filter(this.options.matcher(query));
}
const total = values.length;
if (hasSkip) {
values = values.slice(filters.$skip);
}
if (hasLimit) {
values = values.slice(0, filters.$limit);
}
const result = {
total,
limit: filters.$limit,
skip: filters.$skip || 0,
data: values.map((value) => _select(value, params, this.id))
};
return result;
}
/* Without pagination, we don't have to match every result and gain considerable performance improvements with a breaking for loop. */
if (hasQuery || hasLimit || hasSkip) {
let skipped = 0;
const matcher = this.options.matcher(query);
const matched = [];
if (hasLimit && filters.$limit === 0) {
return [];
}
for (let index = 0, length = values.length; index < length; index++) {
const value = values[index];
if (hasQuery && !matcher(value, index, values)) {
continue;
}
if (hasSkip && filters.$skip > skipped) {
skipped++;
continue;
}
matched.push(_select(value, params, this.id));
if (hasLimit && filters.$limit === matched.length) {
break;
}
}
return matched;
}
return values.map((value) => _select(value, params, this.id));
}
async _get(id, params = {}) {
const { query } = this.getQuery(params);
if (id in this.store) {
const value = this.store[id];
if (this.options.matcher(query)(value)) {
return _select(value, params, this.id);
}
}
throw new errors_1.NotFound(`No record found for id '${id}'`);
}
async _create(data, params = {}) {
if (Array.isArray(data)) {
return Promise.all(data.map((current) => this._create(current, params)));
}
const id = data[this.id] || this._uId++;
const current = commons_1._.extend({}, data, { [this.id]: id });
const result = (this.store[id] = current);
return _select(result, params, this.id);
}
async _update(id, data, params = {}) {
if (id === null || Array.isArray(data)) {
throw new errors_1.BadRequest("You can not replace multiple instances. Did you mean 'patch'?");
}
const oldEntry = await this._get(id);
// We don't want our id to change type if it can be coerced
const oldId = oldEntry[this.id];
// eslint-disable-next-line eqeqeq
id = oldId == id ? oldId : id;
this.store[id] = commons_1._.extend({}, data, { [this.id]: id });
return this._get(id, params);
}
async _patch(id, data, params = {}) {
if (id === null && !this.allowsMulti('patch', params)) {
throw new errors_1.MethodNotAllowed('Can not patch multiple entries');
}
const { query } = this.getQuery(params);
const patchEntry = (entry) => {
const currentId = entry[this.id];
this.store[currentId] = commons_1._.extend(this.store[currentId], commons_1._.omit(data, this.id));
return _select(this.store[currentId], params, this.id);
};
if (id === null) {
const entries = await this.getEntries({
...params,
query
});
return entries.map(patchEntry);
}
return patchEntry(await this._get(id, params)); // Will throw an error if not found
}
async _remove(id, params = {}) {
if (id === null && !this.allowsMulti('remove', params)) {
throw new errors_1.MethodNotAllowed('Can not remove multiple entries');
}
const { query } = this.getQuery(params);
if (id === null) {
const entries = await this.getEntries({
...params,
query
});
return Promise.all(entries.map((current) => this._remove(current[this.id], params)));
}
const entry = await this._get(id, params);
delete this.store[id];
return entry;
}
}
exports.MemoryAdapter = MemoryAdapter;
class MemoryService extends MemoryAdapter {
async find(params) {
return this._find({
...params,
query: await this.sanitizeQuery(params)
});
}
async get(id, params) {
return this._get(id, {
...params,
query: await this.sanitizeQuery(params)
});
}
async create(data, params) {
if (Array.isArray(data) && !this.allowsMulti('create', params)) {
throw new errors_1.MethodNotAllowed('Can not create multiple entries');
}
return this._create(data, params);
}
async update(id, data, params) {
return this._update(id, data, {
...params,
query: await this.sanitizeQuery(params)
});
}
async patch(id, data, params) {
const { $limit, ...query } = await this.sanitizeQuery(params);
return this._patch(id, data, {
...params,
query
});
}
async remove(id, params) {
const { $limit, ...query } = await this.sanitizeQuery(params);
return this._remove(id, {
...params,
query
});
}
}
exports.MemoryService = MemoryService;
function memory(options = {}) {
return new MemoryService(options);
}
//# sourceMappingURL=index.js.map