Pull to refresh
0
0
Ali Nuraldin @Ali_run

Software & Services Architect

Send message
Получилась конструкция, которая работает наподобие git'a.

Есть this._map с данными, которые записываются при загрузке модели из разных источников и this._index, в котором хранятся все изменения (diff) модели от this._map

Естественно, остальные имплементации моделей уже расширяют данный класс.

Base.js
const VError = require('verror');

const { fromComponentsSchemas } = require('../utils/schemaExtractor');

const STATES = {
  UNDEFINED: 'UNDEFINED',
  CREATING: 'CREATING',
  LOADED: 'LOADED',
  DELETED: 'DELETED'
};

/**
 * Base class for our model structure, which takes the responsibility of getting and setting
 */
class ExtendableProxy {
  constructor() {
    return new Proxy(this, {
      set: (target, property, value, receiver) => {
        if (property.indexOf('_') !== 0) { // If not private property -> work with _index
          if (this._state === STATES.UNDEFINED) { // Transition to CREATING state
            this._state = STATES.CREATING;
          }

          if (!this._index[property] && this._map[property].value !== value) { // Check if not in index or not changed
            this._index[property] = Object.assign({}, this._map[property]);
            this._index[property].value = value;
          } else if (this._index[property]) { // If exists -> needs to be updated
            this._index[property].value = value;
          }

          return true;
        }

        target[property] = value;
        return true;
      },
      get: (target, property, receiver) => {
        // Check if not accessing the methods of the class
        // and not the private properties
        // and not symbol
        // so we could validate the state of a model
        if (typeof target[property] !== 'function' && typeof property !== 'symbol' && property.indexOf('_') !== 0) {
          if (this._state === STATES.UNDEFINED) throw new Error('Model is in UNDEFINED state');

          // TODO: Check if getter exists for this property and use it
          return (this._index[property] && this._index[property].value) || (this._map[property] && this._map[property].value);
        }

        return target[property];
      }
    });
  }
}

class Base extends ExtendableProxy {
  /**
   * Sets the source map for Model's variables
   */
  constructor(deviceId, modelName) {
    super();
    this._state = STATES.UNDEFINED;

    this._deviceId = deviceId;

    this._map = fromComponentsSchemas(modelName).properties;

    this._index = {}; // Index of model modifications

    if (!this._map) throw new VError(`Schema ${modelName} is not found`);
  }

  /**
   * Loads whole model from different sources, must be overrided
   * @return {Promise.<T>}
   */
  load() {
    this._state = STATES.LOADED;
  }

  /**
   * Sends the data from model to different sources, must be overrided
   * @return {Promise.<T>}
   */
  commit() {

  }

  /**
   * Deletes the model in different sources, must be overrided
   * @return {Promise.<T>}
   */
  delete() {
    this._state = STATES.DELETED;
  }

  /**
   * Returns an array of names of modified variables
   * @return {Array}
   */
  difference() {
    if (this._state === STATES.UNDEFINED) return [];

    const diff = [];

    for (let key in this._index) {
      diff.push(key);
    }

    return diff;
  }
}

Base.STATES = STATES;

module.exports = Base;

Использовал прокси для создания базового класса модели, зависящей от нескольких источников информации. Очень упрощает реализацию дочерних классов.

Information

Rating
Does not participate
Location
Praha, Hlavni Mesto Praha, Чехия
Registered
Activity