<commit_before>import Ember from 'ember';
import Builder from '../query/builder';
import { SimplePredicate } from '../query/predicate';
import { reloadLocalRecords, syncDownRelatedRecords } from '../utils/reload-local-records';
import isModelInstance from '../utils/is-model-instance';

const { RSVP, isNone, isArray, getOwner, get } = Ember;

/**
  @class Syncer
  @namespace Offline
  @extends Ember.Object
*/
export default Ember.Service.extend({
  /**
    Store that use for making requests in offline mode.
    By default it is set to global instane of {{#crossLink "LocalStore"}}{{/crossLink}} class.

    @property offlineStore
    @type <a href="http://emberjs.com/api/data/classes/DS.Store.html">DS.Store</a>
  */
  offlineStore: undefined,

  /**
  */
  auditEnabled: true,

  /**
   * Initialize offline store.
   *
   * @method init
   * @private
   */
  init: function() {
    let _this = this;

    let localStore = getOwner(this).lookup('store:local');

    _this.set('offlineStore', localStore);
  },

  /**
   * Save specified records into local store (IndexedDB).
   *
   * @method syncDown
   * @public
   * @param {String|DS.Model|Array} descriptor typeName, record, records.
   * @param {Boolean} [reload] If set to true then syncer perform remote reload for data, otherwise data will get from the store.
   * @param {String} [projectionName] Name of projection for remote reload of data. If not set then all properties of record, except navigation properties, will be read.
   * @param {Object} [params] Additional parameters for syncing down.
   * @param {Query.QueryObject} [params.queryObject] QueryObject instance to make query if descriptor is a typeName.
   * @param {Boolean} [params.unloadSyncedRecords] If set to true then synced records will be unloaded from online store.
   * @return {Promie}
   */
  syncDown: function(descriptor, reload, projectionName, params) {
    let _this = this;

    if (typeof descriptor === 'string') {
      return reloadLocalRecords.call(this, descriptor, reload, projectionName, params);

    } else if (isModelInstance(descriptor)) {
      return _this._syncDownRecord(descriptor, reload, projectionName, params);

    } else if (isArray(descriptor)) {
      let updatedRecords = descriptor.map(function(record) {
        return _this._syncDownRecord(record, reload, projectionName, params);
      });
      return RSVP.all(updatedRecords);

    } else {
      throw new Error('Input can only be a string, a DS.Model or an array of DS.Model, but is ' + descriptor);
    }
  },

  /**
   * Remove all records in local store.
   *
   * @method
   * @public
   */
  reset: function() {
    return this.get('offlineStore.adapter').clear();
  },

  /**
   * Saves data to local store.
   *
   * @method _syncDownRecord
   * @param {DS.Model} record Record to save in local store.
   * @param {Boolean} [reload] If set to true then syncer perform remote reload for data, otherwise data will get from the store.
   * @param {String} [projectionName] Name of projection for remote reload of data. If not set then all properties of record, except navigation properties, will be read.
   * @param {Object} [params] Additional parameters for syncing down.
   * @param {Query.QueryObject} [params.queryObject] QueryObject instance to make query if descriptor is a typeName.
   * @param {Boolean} [params.unloadSyncedRecords] If set to true then synced records will be unloaded from online store.
   * @private
   */
  _syncDownRecord: function(record, reload, projectionName, params) {
    var _this = this;

    function saveRecordToLocalStore(store, record, projectionName) {
      let dexieService = getOwner(_this).lookup('service:dexie');
      dexieService.set('queueSyncDownWorksCount', dexieService.get('queueSyncDownWorksCount') + 1);
      let modelName = record.constructor.modelName;
      let modelType = store.modelFor(modelName);
      let projection = isNone(projectionName) ? null : modelType.projections[projectionName];
      let localStore = this.get('offlineStore');
      let localAdapter = localStore.adapterFor(modelName);
      let snapshot = record._createSnapshot();
      let unloadRecordFromStore = () => {

        // TODO: Uncomment this after fix bug with load unloaded models.
        // if (params && params.unloadSyncedRecords) {
        //   if (store.get('onlineStore')) {
        //     store.get('onlineStore').unloadRecord(record);
        //   } else {
        //     store.unloadRecord(record);
        //   }
        // }
      };

      if (record.get('isDeleted')) {
        return localAdapter.deleteRecord(localStore, snapshot.type, snapshot).then(() => {
          dexieService.set('queueSyncDownWorksCount', dexieService.get('queueSyncDownWorksCount') - 1);
        }).catch((reason) => {
          dexieService.set('queueSyncDownWorksCount', dexieService.get('queueSyncDownWorksCount') - 1);
          Ember.Logger.error(reason);
        }).finally(unloadRecordFromStore);
      } else {
        return localAdapter.updateOrCreate(localStore, snapshot.type, snapshot).then(function() {
          dexieService.set('queueSyncDownWorksCount', dexieService.get('queueSyncDownWorksCount') - 1);
          let offlineGlobals = Ember.getOwner(_this).lookup('service:offline-globals');
          if (projection || (!projection && offlineGlobals.get('allowSyncDownRelatedRecordsWithoutProjection'))) {
            return syncDownRelatedRecords.call(_this, store, record, localAdapter, localStore, projection, params);
          } else {
            Ember.Logger.warn('It does not allow to sync down related records without specified projection. ' +
              'Please specify option "allowSyncDownRelatedRecordsWithoutProjection" in environment.js');
            return RSVP.resolve();
          }
        }).catch((reason) => {
          dexieService.set('queueSyncDownWorksCount', dexieService.get('queueSyncDownWorksCount') - 1);
          Ember.Logger.error(reason);
        }).finally(unloadRecordFromStore);
      }
    }

    var store = getOwner(this).lookup('service:store');
    if (reload) {
      let modelName = record.constructor.modelName;
      let options = {
        reload: true,
        useOnlineStore: true
      };
      options = isNone(projectionName) ? options : Ember.$.extend(true, options, { projection: projectionName });
      return store.findRecord(modelName, record.id, options).then(function(reloadedRecord) {

        // TODO: Uncomment this after fix bug with load unloaded models.
        // store.get('onlineStore').unloadRecord(modelName);
        return saveRecordToLocalStore.call(_this, store, reloadedRecord, projectionName);
      });
    } else {
      return saveRecordToLocalStore.call(_this, store, record, projectionName);
    }
  },

  /**
  */
  syncUp(continueOnError) {
    let dexieService = getOwner(this).lookup('service:dexie');
    let store = getOwner(this).lookup('service:store');
    let modelName = 'i-c-s-soft-s-t-o-r-m-n-e-t-business-audit-objects-audit-entity';
    let predicate = new SimplePredicate('executionResult', 'eq', 'Unexecuted')
      .or(new SimplePredicate('executionResult', 'eq', 'Failed'));
    let builder = new Builder(store, modelName)
      .selectByProjection('AuditEntityE')
      .orderBy('operationTime')
      .where(predicate);
    return this.get('offlineStore').query(modelName, builder.build()).then((jobs) => {
      dexieService.set('queueSyncUpTotalWorksCount', jobs.get('length'));
      return this._runJobs(store, jobs, continueOnError);
    });
  },

  /**
  */
  createJob(record) {
    let _this = this;
    return new RSVP.Promise((resolve, reject) => {
      _this._createAuditEntity(record).then((auditEntity) => {
        _this._createAuditFields(auditEntity, record).then((auditEntity) => {
          resolve(auditEntity);
        }).catch((reason) => {
          reject(reason);
        });
      });
    });
  },

  /**<commit_msg>Chore syncer service same but short<commit_after>import Ember from 'ember';
import Builder from '../query/builder';
import { SimplePredicate } from '../query/predicate';
import { reloadLocalRecords, syncDownRelatedRecords } from '../utils/reload-local-records';
import isModelInstance from '../utils/is-model-instance';

const { RSVP, isNone, isArray, getOwner, get } = Ember;

/**
  @class Syncer
  @namespace Offline
  @extends Ember.Object
*/
export default Ember.Service.extend({
  /**
    Store that use for making requests in offline mode.
    By default it is set to global instane of {{#crossLink "LocalStore"}}{{/crossLink}} class.

    @property offlineStore
    @type <a href="http://emberjs.com/api/data/classes/DS.Store.html">DS.Store</a>
  */
  offlineStore: undefined,

  /**
  */
  auditEnabled: true,

  /**
   * Initialize offline store.
   *
   * @method init
   * @private
   */
  init: function() {
    let _this = this;

    let localStore = getOwner(this).lookup('store:local');

    _this.set('offlineStore', localStore);
  },

  /**
   * Save specified records into local store (IndexedDB).
   *
   * @method syncDown
   * @public
   * @param {String|DS.Model|Array} descriptor typeName, record, records.
   * @param {Boolean} [reload] If set to true then syncer perform remote reload for data, otherwise data will get from the store.
   * @param {String} [projectionName] Name of projection for remote reload of data. If not set then all properties of record, except navigation properties, will be read.
   * @param {Object} [params] Additional parameters for syncing down.
   * @param {Query.QueryObject} [params.queryObject] QueryObject instance to make query if descriptor is a typeName.
   * @param {Boolean} [params.unloadSyncedRecords] If set to true then synced records will be unloaded from online store.
   * @return {Promie}
   */
  syncDown: function(descriptor, reload, projectionName, params) {
    let _this = this;

    if (typeof descriptor === 'string') {
      return reloadLocalRecords.call(this, descriptor, reload, projectionName, params);

    } else if (isModelInstance(descriptor)) {
      return _this._syncDownRecord(descriptor, reload, projectionName, params);

    } else if (isArray(descriptor)) {
      let updatedRecords = descriptor.map(function(record) {
        return _this._syncDownRecord(record, reload, projectionName, params);
      });
      return RSVP.all(updatedRecords);

    } else {
      throw new Error('Input can only be a string, a DS.Model or an array of DS.Model, but is ' + descriptor);
    }
  },

  /**
   * Remove all records in local store.
   *
   * @method
   * @public
   */
  reset: function() {
    return this.get('offlineStore.adapter').clear();
  },

  /**
   * Saves data to local store.
   *
   * @method _syncDownRecord
   * @param {DS.Model} record Record to save in local store.
   * @param {Boolean} [reload] If set to true then syncer perform remote reload for data, otherwise data will get from the store.
   * @param {String} [projectionName] Name of projection for remote reload of data. If not set then all properties of record, except navigation properties, will be read.
   * @param {Object} [params] Additional parameters for syncing down.
   * @param {Query.QueryObject} [params.queryObject] QueryObject instance to make query if descriptor is a typeName.
   * @param {Boolean} [params.unloadSyncedRecords] If set to true then synced records will be unloaded from online store.
   * @private
   */
  _syncDownRecord: function(record, reload, projectionName, params) {
    var _this = this;

    function saveRecordToLocalStore(store, record, projectionName) {
      let dexieService = getOwner(_this).lookup('service:dexie');
      dexieService.set('queueSyncDownWorksCount', dexieService.get('queueSyncDownWorksCount') + 1);
      let modelName = record.constructor.modelName;
      let modelType = store.modelFor(modelName);
      let projection = isNone(projectionName) ? null : modelType.projections[projectionName];
      let localStore = this.get('offlineStore');
      let localAdapter = localStore.adapterFor(modelName);
      let snapshot = record._createSnapshot();
      let unloadRecordFromStore = () => {

        // TODO: Uncomment this after fix bug with load unloaded models.
        // if (params && params.unloadSyncedRecords) {
        //   if (store.get('onlineStore')) {
        //     store.get('onlineStore').unloadRecord(record);
        //   } else {
        //     store.unloadRecord(record);
        //   }
        // }
      };

      if (record.get('isDeleted')) {
        return localAdapter.deleteRecord(localStore, snapshot.type, snapshot).then(() => {
          dexieService.set('queueSyncDownWorksCount', dexieService.get('queueSyncDownWorksCount') - 1);
        }).catch((reason) => {
          dexieService.set('queueSyncDownWorksCount', dexieService.get('queueSyncDownWorksCount') - 1);
          Ember.Logger.error(reason);
        }).finally(unloadRecordFromStore);
      } else {
        return localAdapter.updateOrCreate(localStore, snapshot.type, snapshot).then(function() {
          dexieService.set('queueSyncDownWorksCount', dexieService.get('queueSyncDownWorksCount') - 1);
          let offlineGlobals = Ember.getOwner(_this).lookup('service:offline-globals');
          if (projection || (!projection && offlineGlobals.get('allowSyncDownRelatedRecordsWithoutProjection'))) {
            return syncDownRelatedRecords.call(_this, store, record, localAdapter, localStore, projection, params);
          } else {
            Ember.Logger.warn('It does not allow to sync down related records without specified projection. ' +
              'Please specify option "allowSyncDownRelatedRecordsWithoutProjection" in environment.js');
            return RSVP.resolve();
          }
        }).catch((reason) => {
          dexieService.set('queueSyncDownWorksCount', dexieService.get('queueSyncDownWorksCount') - 1);
          Ember.Logger.error(reason);
        }).finally(unloadRecordFromStore);
      }
    }

    var store = getOwner(this).lookup('service:store');
    if (reload) {
      let modelName = record.constructor.modelName;
      let options = {
        reload: true,
        useOnlineStore: true
      };
      options = isNone(projectionName) ? options : Ember.$.extend(true, options, { projection: projectionName });
      return store.findRecord(modelName, record.id, options).then(function(reloadedRecord) {

        // TODO: Uncomment this after fix bug with load unloaded models.
        // store.get('onlineStore').unloadRecord(modelName);
        return saveRecordToLocalStore.call(_this, store, reloadedRecord, projectionName);
      });
    } else {
      return saveRecordToLocalStore.call(_this, store, record, projectionName);
    }
  },

  /**
  */
  syncUp(continueOnError) {
    let dexieService = getOwner(this).lookup('service:dexie');
    let store = getOwner(this).lookup('service:store');
    let modelName = 'i-c-s-soft-s-t-o-r-m-n-e-t-business-audit-objects-audit-entity';
    let predicate = new SimplePredicate('executionResult', 'eq', 'Unexecuted')
      .or(new SimplePredicate('executionResult', 'eq', 'Failed'));
    let builder = new Builder(store, modelName)
      .selectByProjection('AuditEntityE')
      .orderBy('operationTime')
      .where(predicate);
    return this.get('offlineStore').query(modelName, builder.build()).then((jobs) => {
      dexieService.set('queueSyncUpTotalWorksCount', jobs.get('length'));
      return this._runJobs(store, jobs, continueOnError);
    });
  },

  /**
  */
  createJob(record) {
    return new RSVP.Promise((resolve, reject) => {
      this._createAuditEntity(record).then((auditEntity) => {
        this._createAuditFields(auditEntity, record).then(resolve, reject);
      });
    });
  },

  /**
{'fraction_non_alphanumeric': 0.12422360248447205, 'fraction_numerical': 0.0006337938902268982, 'mean_word_length': 3.3301317233809002, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 23, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '627603', 'n_tokens_mistral': 4598, 'n_tokens_neox': 4437, 'n_words': 1150}