github.com/outbrain/consul@v1.4.5/ui-v2/app/adapters/kv.js (about)

     1  import Adapter, {
     2    REQUEST_CREATE,
     3    REQUEST_UPDATE,
     4    REQUEST_DELETE,
     5    DATACENTER_QUERY_PARAM as API_DATACENTER_KEY,
     6  } from './application';
     7  import isFolder from 'consul-ui/utils/isFolder';
     8  import injectableRequestToJQueryAjaxHash from 'consul-ui/utils/injectableRequestToJQueryAjaxHash';
     9  import { typeOf } from '@ember/utils';
    10  import { get } from '@ember/object';
    11  import { inject as service } from '@ember/service';
    12  
    13  import keyToArray from 'consul-ui/utils/keyToArray';
    14  import removeNull from 'consul-ui/utils/remove-null';
    15  
    16  import { PRIMARY_KEY, SLUG_KEY } from 'consul-ui/models/kv';
    17  import { FOREIGN_KEY as DATACENTER_KEY } from 'consul-ui/models/dc';
    18  import { PUT as HTTP_PUT, DELETE as HTTP_DELETE } from 'consul-ui/utils/http/method';
    19  import { OK as HTTP_OK } from 'consul-ui/utils/http/status';
    20  
    21  const API_KEYS_KEY = 'keys';
    22  const stringify = function(obj) {
    23    if (typeOf(obj) === 'string') {
    24      return obj;
    25    }
    26    return JSON.stringify(obj);
    27  };
    28  export default Adapter.extend({
    29    // There is no code path that can avoid the payload of a PUT request from
    30    // going via JSON.stringify.
    31    // Therefore a string payload of 'foobar' will always be encoded to '"foobar"'
    32    //
    33    // This means we have no other choice but rewriting the entire codepath or
    34    // overwriting the private `_requestToJQueryAjaxHash` method
    35    //
    36    // The `injectableRequestToJQueryAjaxHash` function makes the JSON object
    37    // injectable, meaning we can copy letter for letter the sourcecode of
    38    // `_requestToJQueryAjaxHash`, which means we can compare it with the original
    39    // private method within a test (`tests/unit/utils/injectableRequestToJQueryAjaxHash.js`).
    40    // This means, if `_requestToJQueryAjaxHash` changes between Ember versions
    41    // we will know about it
    42  
    43    _requestToJQueryAjaxHash: injectableRequestToJQueryAjaxHash({
    44      stringify: stringify,
    45    }),
    46    decoder: service('atob'),
    47    urlForQuery: function(query, modelName) {
    48      if (typeof query.id === 'undefined') {
    49        throw new Error('You must specify an id');
    50      }
    51      // append keys here otherwise query.keys will add an '='
    52      return this.appendURL('kv', keyToArray(query.id), {
    53        ...{
    54          [API_KEYS_KEY]: null,
    55        },
    56        ...this.cleanQuery(query),
    57      });
    58    },
    59    urlForQueryRecord: function(query, modelName) {
    60      if (typeof query.id === 'undefined') {
    61        throw new Error('You must specify an id');
    62      }
    63      return this.appendURL('kv', keyToArray(query.id), this.cleanQuery(query));
    64    },
    65    urlForCreateRecord: function(modelName, snapshot) {
    66      return this.appendURL('kv', keyToArray(snapshot.attr(SLUG_KEY)), {
    67        [API_DATACENTER_KEY]: snapshot.attr(DATACENTER_KEY),
    68      });
    69    },
    70    urlForUpdateRecord: function(id, modelName, snapshot) {
    71      return this.appendURL('kv', keyToArray(snapshot.attr(SLUG_KEY)), {
    72        [API_DATACENTER_KEY]: snapshot.attr(DATACENTER_KEY),
    73      });
    74    },
    75    urlForDeleteRecord: function(id, modelName, snapshot) {
    76      const query = {
    77        [API_DATACENTER_KEY]: snapshot.attr(DATACENTER_KEY),
    78      };
    79      if (isFolder(snapshot.attr(SLUG_KEY))) {
    80        query.recurse = null;
    81      }
    82      return this.appendURL('kv', keyToArray(snapshot.attr(SLUG_KEY)), query);
    83    },
    84    slugFromURL: function(url) {
    85      // keys don't follow the 'last part of the url' rule as they contain slashes
    86      return decodeURIComponent(
    87        url.pathname
    88          .split('/')
    89          .splice(3)
    90          .join('/')
    91      );
    92    },
    93    isQueryRecord: function(url, method) {
    94      return !url.searchParams.has(API_KEYS_KEY);
    95    },
    96    handleBatchResponse: function(url, response, primary, slug) {
    97      const dc = url.searchParams.get(API_DATACENTER_KEY) || '';
    98      return response.map((item, i, arr) => {
    99        return {
   100          [DATACENTER_KEY]: dc,
   101          [PRIMARY_KEY]: this.uidForURL(url, item),
   102          [SLUG_KEY]: item,
   103        };
   104      });
   105    },
   106    // handleSingleResponse: function(url, response, primary, slug) {
   107    //   return this._super(url, removeNull(response[0]), PRIMARY_KEY, SLUG_KEY);
   108    // },
   109    handleResponse: function(status, headers, payload, requestData) {
   110      let response = payload;
   111      const method = requestData.method;
   112      if (status === HTTP_OK) {
   113        const url = this.parseURL(requestData.url);
   114        switch (true) {
   115          case response === true:
   116            response = this.handleBooleanResponse(url, response, PRIMARY_KEY, SLUG_KEY);
   117            break;
   118          case this.isQueryRecord(url, method):
   119            response = this.handleSingleResponse(url, removeNull(response[0]), PRIMARY_KEY, SLUG_KEY);
   120            break;
   121          default:
   122            response = this.handleBatchResponse(url, response, PRIMARY_KEY, SLUG_KEY);
   123        }
   124      }
   125      return this._super(status, headers, response, requestData);
   126    },
   127    dataForRequest: function(params) {
   128      const data = this._super(...arguments);
   129      let value = '';
   130      switch (params.requestType) {
   131        case REQUEST_UPDATE:
   132        case REQUEST_CREATE:
   133          value = data.kv.Value;
   134          if (typeof value === 'string') {
   135            return get(this, 'decoder').execute(value);
   136          }
   137          return null;
   138      }
   139    },
   140    methodForRequest: function(params) {
   141      switch (params.requestType) {
   142        case REQUEST_DELETE:
   143          return HTTP_DELETE;
   144        case REQUEST_CREATE:
   145          return HTTP_PUT;
   146      }
   147      return this._super(...arguments);
   148    },
   149  });