github.com/emate/nomad@v0.8.2-wo-binpacking/ui/app/adapters/watchable.js (about)

     1  import { get, computed } from '@ember/object';
     2  import { assign } from '@ember/polyfills';
     3  import { inject as service } from '@ember/service';
     4  import queryString from 'npm:query-string';
     5  import ApplicationAdapter from './application';
     6  import { AbortError } from 'ember-data/adapters/errors';
     7  
     8  export default ApplicationAdapter.extend({
     9    watchList: service(),
    10    store: service(),
    11  
    12    xhrs: computed(function() {
    13      return {
    14        list: {},
    15        track(key, xhr) {
    16          if (this.list[key]) {
    17            this.list[key].push(xhr);
    18          } else {
    19            this.list[key] = [xhr];
    20          }
    21        },
    22        cancel(key) {
    23          while (this.list[key] && this.list[key].length) {
    24            this.remove(key, this.list[key][0]);
    25          }
    26        },
    27        remove(key, xhr) {
    28          if (this.list[key]) {
    29            xhr.abort();
    30            this.list[key].removeObject(xhr);
    31          }
    32        },
    33      };
    34    }),
    35  
    36    ajaxOptions() {
    37      const ajaxOptions = this._super(...arguments);
    38      const key = this.xhrKey(...arguments);
    39  
    40      const previousBeforeSend = ajaxOptions.beforeSend;
    41      ajaxOptions.beforeSend = function(jqXHR) {
    42        if (previousBeforeSend) {
    43          previousBeforeSend(...arguments);
    44        }
    45        this.get('xhrs').track(key, jqXHR);
    46        jqXHR.always(() => {
    47          this.get('xhrs').remove(key, jqXHR);
    48        });
    49      };
    50  
    51      return ajaxOptions;
    52    },
    53  
    54    xhrKey(url /* method, options */) {
    55      return url;
    56    },
    57  
    58    findAll(store, type, sinceToken, snapshotRecordArray, additionalParams = {}) {
    59      const params = assign(this.buildQuery(), additionalParams);
    60      const url = this.urlForFindAll(type.modelName);
    61  
    62      if (get(snapshotRecordArray || {}, 'adapterOptions.watch')) {
    63        params.index = this.get('watchList').getIndexFor(url);
    64      }
    65  
    66      return this.ajax(url, 'GET', {
    67        data: params,
    68      });
    69    },
    70  
    71    findRecord(store, type, id, snapshot, additionalParams = {}) {
    72      let [url, params] = this.buildURL(type.modelName, id, snapshot, 'findRecord').split('?');
    73      params = assign(queryString.parse(params) || {}, this.buildQuery(), additionalParams);
    74  
    75      if (get(snapshot || {}, 'adapterOptions.watch')) {
    76        params.index = this.get('watchList').getIndexFor(url);
    77      }
    78  
    79      return this.ajax(url, 'GET', {
    80        data: params,
    81      }).catch(error => {
    82        if (error instanceof AbortError) {
    83          return;
    84        }
    85        throw error;
    86      });
    87    },
    88  
    89    reloadRelationship(model, relationshipName, watch = false) {
    90      const relationship = model.relationshipFor(relationshipName);
    91      if (relationship.kind !== 'belongsTo' && relationship.kind !== 'hasMany') {
    92        throw new Error(
    93          `${relationship.key} must be a belongsTo or hasMany, instead it was ${relationship.kind}`
    94        );
    95      } else {
    96        const url = model[relationship.kind](relationship.key).link();
    97        let params = {};
    98  
    99        if (watch) {
   100          params.index = this.get('watchList').getIndexFor(url);
   101        }
   102  
   103        // Avoid duplicating existing query params by passing them to ajax
   104        // in the URL and in options.data
   105        if (url.includes('?')) {
   106          const paramsInUrl = queryString.parse(url.split('?')[1]);
   107          Object.keys(paramsInUrl).forEach(key => {
   108            delete params[key];
   109          });
   110        }
   111  
   112        return this.ajax(url, 'GET', {
   113          data: params,
   114        }).then(
   115          json => {
   116            const store = this.get('store');
   117            const normalizeMethod =
   118              relationship.kind === 'belongsTo'
   119                ? 'normalizeFindBelongsToResponse'
   120                : 'normalizeFindHasManyResponse';
   121            const serializer = store.serializerFor(relationship.type);
   122            const modelClass = store.modelFor(relationship.type);
   123            const normalizedData = serializer[normalizeMethod](store, modelClass, json);
   124            store.push(normalizedData);
   125          },
   126          error => {
   127            if (error instanceof AbortError) {
   128              return relationship.kind === 'belongsTo' ? {} : [];
   129            }
   130            throw error;
   131          }
   132        );
   133      }
   134    },
   135  
   136    handleResponse(status, headers, payload, requestData) {
   137      // Some browsers lowercase all headers. Others keep them
   138      // case sensitive.
   139      const newIndex = headers['x-nomad-index'] || headers['X-Nomad-Index'];
   140      if (newIndex) {
   141        this.get('watchList').setIndexFor(requestData.url, newIndex);
   142      }
   143  
   144      return this._super(...arguments);
   145    },
   146  
   147    cancelFindRecord(modelName, id) {
   148      if (!modelName || id == null) {
   149        return;
   150      }
   151      const url = this.urlForFindRecord(id, modelName);
   152      this.get('xhrs').cancel(url);
   153    },
   154  
   155    cancelFindAll(modelName) {
   156      if (!modelName) {
   157        return;
   158      }
   159      let url = this.urlForFindAll(modelName);
   160      const params = queryString.stringify(this.buildQuery());
   161      if (params) {
   162        url = `${url}?${params}`;
   163      }
   164      this.get('xhrs').cancel(url);
   165    },
   166  
   167    cancelReloadRelationship(model, relationshipName) {
   168      if (!model || !relationshipName) {
   169        return;
   170      }
   171      const relationship = model.relationshipFor(relationshipName);
   172      if (relationship.kind !== 'belongsTo' && relationship.kind !== 'hasMany') {
   173        throw new Error(
   174          `${relationship.key} must be a belongsTo or hasMany, instead it was ${relationship.kind}`
   175        );
   176      } else {
   177        const url = model[relationship.kind](relationship.key).link();
   178        this.get('xhrs').cancel(url);
   179      }
   180    },
   181  });