| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448 |
- import {Adapter} from '../adapter.js';
- import {cloneDeep, capitalize} from '../../utils/index.js';
- import {InvalidArgumentError} from '../../errors/index.js';
- import {DataType, ModelDefinitionUtils} from '../../definition/index.js';
- import {
- SliceClauseTool,
- WhereClauseTool,
- OrderClauseTool,
- } from '../../filter/index.js';
- /**
- * Memory adapter.
- */
- export class MemoryAdapter extends Adapter {
- /**
- * Tables.
- *
- * @type {Map<string, Map<number, Record<string, any>>>}
- */
- _tables = new Map();
- /**
- * Last ids.
- *
- * @type {Map<string, number>}
- */
- _lastIds = new Map();
- /**
- * Get table or create.
- *
- * @param {string} modelName
- * @returns {Map<number, object>}
- */
- _getTableOrCreate(modelName) {
- const tableName =
- this.getService(ModelDefinitionUtils).getTableNameByModelName(modelName);
- let table = this._tables.get(tableName);
- if (table) return table;
- table = new Map();
- this._tables.set(tableName, table);
- return table;
- }
- /**
- * Gen next id value.
- *
- * @param {string} modelName
- * @param {string} propName
- * @returns {number}
- */
- _genNextIdValue(modelName, propName) {
- const modelUtils = this.getService(ModelDefinitionUtils);
- const propType = modelUtils.getDataTypeByPropertyName(modelName, propName);
- if (propType !== DataType.ANY && propType !== DataType.NUMBER) {
- throw new InvalidArgumentError(
- 'The memory adapter able to generate only Number identifiers, ' +
- 'but the primary key %v of the model %v is defined as %s. ' +
- 'Do provide your own value for the %v property, or change the type ' +
- 'in the primary key definition to a Number that will be ' +
- 'generated automatically.',
- propName,
- modelName,
- capitalize(propType),
- propName,
- );
- }
- const tableName = modelUtils.getTableNameByModelName(modelName);
- const table = this._getTableOrCreate(modelName);
- let nextId = this._lastIds.get(tableName) ?? 0;
- do {
- nextId++;
- } while (table.has(nextId));
- this._lastIds.set(tableName, nextId);
- return nextId;
- }
- /**
- * Update last id value if needed.
- *
- * Если переданное значение последнего использованного
- * идентификатора больше текущего, то текущее значение
- * перезаписывается полученным.
- *
- * @param {string} modelName
- * @param {number} idValue
- */
- _updateLastIdValueIfNeeded(modelName, idValue) {
- const tableName =
- this.getService(ModelDefinitionUtils).getTableNameByModelName(modelName);
- const currentLastId = this._lastIds.get(tableName) ?? 0;
- if (idValue > currentLastId) {
- this._lastIds.set(tableName, idValue);
- }
- }
- /**
- * Create
- *
- * @param {string} modelName
- * @param {object} modelData
- * @param {object|undefined} filter
- * @returns {Promise<object>}
- */
- // eslint-disable-next-line no-unused-vars
- async create(modelName, modelData, filter = undefined) {
- const pkPropName =
- this.getService(ModelDefinitionUtils).getPrimaryKeyAsPropertyName(
- modelName,
- );
- let idValue = modelData[pkPropName];
- if (idValue == null || idValue === '' || idValue === 0) {
- idValue = this._genNextIdValue(modelName, pkPropName);
- }
- // если идентификатор передан вручную и является числом,
- // то значение последнего использованного идентификатора
- // обновляется на полученное
- else if (typeof idValue === 'number') {
- this._updateLastIdValueIfNeeded(modelName, idValue);
- }
- const table = this._getTableOrCreate(modelName);
- if (table.has(idValue))
- throw new InvalidArgumentError(
- 'The value %v of the primary key %v already exists in the model %v.',
- idValue,
- pkPropName,
- modelName,
- );
- modelData = cloneDeep(modelData);
- modelData[pkPropName] = idValue;
- const tableData = this.getService(
- ModelDefinitionUtils,
- ).convertPropertyNamesToColumnNames(modelName, modelData);
- table.set(idValue, tableData);
- return this.getService(
- ModelDefinitionUtils,
- ).convertColumnNamesToPropertyNames(modelName, tableData);
- }
- /**
- * Replace by id.
- *
- * @param {string} modelName
- * @param {string|number} id
- * @param {object} modelData
- * @param {object|undefined} filter
- * @returns {Promise<object>}
- */
- // eslint-disable-next-line no-unused-vars
- async replaceById(modelName, id, modelData, filter = undefined) {
- const table = this._getTableOrCreate(modelName);
- const isExists = table.has(id);
- const pkPropName =
- this.getService(ModelDefinitionUtils).getPrimaryKeyAsPropertyName(
- modelName,
- );
- if (!isExists)
- throw new InvalidArgumentError(
- 'The value %v of the primary key %v does not exist in the model %v.',
- id,
- pkPropName,
- modelName,
- );
- modelData = cloneDeep(modelData);
- modelData[pkPropName] = id;
- const tableData = this.getService(
- ModelDefinitionUtils,
- ).convertPropertyNamesToColumnNames(modelName, modelData);
- table.set(id, tableData);
- return this.getService(
- ModelDefinitionUtils,
- ).convertColumnNamesToPropertyNames(modelName, tableData);
- }
- /**
- * Replace or create.
- *
- * @param {string} modelName
- * @param {object} modelData
- * @param {object|undefined} filter
- * @returns {Promise<object>}
- */
- // eslint-disable-next-line no-unused-vars
- async replaceOrCreate(modelName, modelData, filter = undefined) {
- const pkPropName =
- this.getService(ModelDefinitionUtils).getPrimaryKeyAsPropertyName(
- modelName,
- );
- let idValue = modelData[pkPropName];
- if (idValue == null || idValue === '' || idValue === 0) {
- idValue = this._genNextIdValue(modelName, pkPropName);
- }
- // если идентификатор передан вручную и является числом,
- // то значение последнего использованного идентификатора
- // обновляется на полученное
- else if (typeof idValue === 'number') {
- this._updateLastIdValueIfNeeded(modelName, idValue);
- }
- const table = this._getTableOrCreate(modelName);
- modelData = cloneDeep(modelData);
- modelData[pkPropName] = idValue;
- const tableData = this.getService(
- ModelDefinitionUtils,
- ).convertPropertyNamesToColumnNames(modelName, modelData);
- table.set(idValue, tableData);
- return this.getService(
- ModelDefinitionUtils,
- ).convertColumnNamesToPropertyNames(modelName, tableData);
- }
- /**
- * Patch.
- *
- * @param {string} modelName
- * @param {object} modelData
- * @param {object|undefined} where
- * @returns {Promise<number>}
- */
- async patch(modelName, modelData, where = undefined) {
- const table = this._getTableOrCreate(modelName);
- const tableItems = Array.from(table.values());
- if (!tableItems.length) return 0;
- let modelItems = tableItems.map(tableItem =>
- this.getService(ModelDefinitionUtils).convertColumnNamesToPropertyNames(
- modelName,
- tableItem,
- ),
- );
- if (where && typeof where === 'object')
- modelItems = this.getService(WhereClauseTool).filter(modelItems, where);
- const size = modelItems.length;
- const pkPropName =
- this.getService(ModelDefinitionUtils).getPrimaryKeyAsPropertyName(
- modelName,
- );
- modelData = cloneDeep(modelData);
- delete modelData[pkPropName];
- modelItems.forEach(existingModelData => {
- const mergedModelData = Object.assign({}, existingModelData, modelData);
- const mergedTableData = this.getService(
- ModelDefinitionUtils,
- ).convertPropertyNamesToColumnNames(modelName, mergedModelData);
- const idValue = existingModelData[pkPropName];
- table.set(idValue, mergedTableData);
- });
- return size;
- }
- /**
- * Patch by id.
- *
- * @param {string} modelName
- * @param {string|number} id
- * @param {object} modelData
- * @param {object|undefined} filter
- * @returns {Promise<object>}
- */
- // eslint-disable-next-line no-unused-vars
- async patchById(modelName, id, modelData, filter = undefined) {
- const table = this._getTableOrCreate(modelName);
- const existingTableData = table.get(id);
- const pkPropName =
- this.getService(ModelDefinitionUtils).getPrimaryKeyAsPropertyName(
- modelName,
- );
- if (existingTableData == null)
- throw new InvalidArgumentError(
- 'The value %v of the primary key %v does not exist in the model %v.',
- id,
- pkPropName,
- modelName,
- );
- modelData = cloneDeep(modelData);
- delete modelData[pkPropName];
- const existingModelData = this.getService(
- ModelDefinitionUtils,
- ).convertColumnNamesToPropertyNames(modelName, existingTableData);
- const mergedModelData = Object.assign({}, existingModelData, modelData);
- const mergedTableData = this.getService(
- ModelDefinitionUtils,
- ).convertPropertyNamesToColumnNames(modelName, mergedModelData);
- table.set(id, mergedTableData);
- return this.getService(
- ModelDefinitionUtils,
- ).convertColumnNamesToPropertyNames(modelName, mergedTableData);
- }
- /**
- * Find.
- *
- * @param {string} modelName
- * @param {object|undefined} filter
- * @returns {Promise<object[]>}
- */
- async find(modelName, filter = undefined) {
- const table = this._getTableOrCreate(modelName);
- const tableItems = Array.from(table.values());
- let modelItems = tableItems.map(tableItem =>
- this.getService(ModelDefinitionUtils).convertColumnNamesToPropertyNames(
- modelName,
- tableItem,
- ),
- );
- if (filter && typeof filter === 'object') {
- if (filter.where)
- modelItems = this.getService(WhereClauseTool).filter(
- modelItems,
- filter.where,
- );
- if (filter.skip || filter.limit)
- modelItems = this.getService(SliceClauseTool).slice(
- modelItems,
- filter.skip,
- filter.limit,
- );
- if (filter.order)
- this.getService(OrderClauseTool).sort(modelItems, filter.order);
- }
- return modelItems;
- }
- /**
- * Find by id.
- *
- * @param {string} modelName
- * @param {string|number} id
- * @param {object|undefined} filter
- * @returns {Promise<object>}
- */
- // eslint-disable-next-line no-unused-vars
- async findById(modelName, id, filter = undefined) {
- const table = this._getTableOrCreate(modelName);
- const tableData = table.get(id);
- const pkPropName =
- this.getService(ModelDefinitionUtils).getPrimaryKeyAsPropertyName(
- modelName,
- );
- if (!tableData)
- throw new InvalidArgumentError(
- 'The value %v of the primary key %v does not exist in the model %v.',
- id,
- pkPropName,
- modelName,
- );
- return this.getService(
- ModelDefinitionUtils,
- ).convertColumnNamesToPropertyNames(modelName, tableData);
- }
- /**
- * Delete.
- *
- * @param {string} modelName
- * @param {object|undefined} where
- * @returns {Promise<number>}
- */
- async delete(modelName, where = undefined) {
- const table = this._getTableOrCreate(modelName);
- const tableItems = Array.from(table.values());
- if (!tableItems.length) return 0;
- let modelItems = tableItems.map(tableItem =>
- this.getService(ModelDefinitionUtils).convertColumnNamesToPropertyNames(
- modelName,
- tableItem,
- ),
- );
- if (where && typeof where === 'object')
- modelItems = this.getService(WhereClauseTool).filter(modelItems, where);
- const size = modelItems.length;
- const idPropName =
- this.getService(ModelDefinitionUtils).getPrimaryKeyAsPropertyName(
- modelName,
- );
- modelItems.forEach(modelData => {
- const idValue = modelData[idPropName];
- table.delete(idValue);
- });
- return size;
- }
- /**
- * Delete by id.
- *
- * @param {string} modelName
- * @param {string|number} id
- * @returns {Promise<boolean>}
- */
- async deleteById(modelName, id) {
- const table = this._getTableOrCreate(modelName);
- const isExists = table.has(id);
- table.delete(id);
- return isExists;
- }
- /**
- * Exists.
- *
- * @param {string} modelName
- * @param {string|number} id
- * @returns {Promise<boolean>}
- */
- async exists(modelName, id) {
- const table = this._getTableOrCreate(modelName);
- return table.has(id);
- }
- /**
- * Count.
- *
- * @param {string} modelName
- * @param {object|undefined} where
- * @returns {Promise<number>}
- */
- async count(modelName, where = undefined) {
- const table = this._getTableOrCreate(modelName);
- const tableItems = Array.from(table.values());
- let modelItems = tableItems.map(tableItem =>
- this.getService(ModelDefinitionUtils).convertColumnNamesToPropertyNames(
- modelName,
- tableItem,
- ),
- );
- if (where && typeof where === 'object')
- modelItems = this.getService(WhereClauseTool).filter(modelItems, where);
- return modelItems.length;
- }
- }
|