github.com/hernad/nomad@v1.6.112/ui/app/serializers/application.js (about)

     1  /**
     2   * Copyright (c) HashiCorp, Inc.
     3   * SPDX-License-Identifier: MPL-2.0
     4   */
     5  
     6  import { copy } from 'ember-copy';
     7  import { get } from '@ember/object';
     8  import { makeArray } from '@ember/array';
     9  import JSONSerializer from '@ember-data/serializer/json';
    10  import { pluralize, singularize } from 'ember-inflector';
    11  import removeRecord from '../utils/remove-record';
    12  import { assign } from '@ember/polyfills';
    13  import classic from 'ember-classic-decorator';
    14  import { camelize, capitalize, dasherize } from '@ember/string';
    15  @classic
    16  export default class Application extends JSONSerializer {
    17    primaryKey = 'ID';
    18  
    19    /**
    20      A list of keys that are converted to empty arrays if their value is null.
    21  
    22      arrayNullOverrides = ['Array'];
    23      { Array: null } => { Array: [] }
    24  
    25      @property arrayNullOverrides
    26      @type String[]
    27     */
    28    arrayNullOverrides = null;
    29  
    30    /**
    31      A list of keys that are converted to empty objects if their value is null.
    32  
    33      objectNullOverrides = ['Object'];
    34      { Object: null } => { Object: {} }
    35  
    36      @property objectNullOverrides
    37      @type String[]
    38     */
    39    objectNullOverrides = null;
    40  
    41    /**
    42      A list of keys or objects to convert a map into an array of maps with the original map keys as Name properties.
    43  
    44      mapToArray = ['Map'];
    45      { Map: { a: { x: 1 } } } => { Map: [ { Name: 'a', x: 1 }] }
    46  
    47      mapToArray = [{ beforeName: 'M', afterName: 'Map' }];
    48      { M: { a: { x: 1 } } } => { Map: [ { Name: 'a', x: 1 }] }
    49  
    50      @property mapToArray
    51      @type (String|Object)[]
    52     */
    53    mapToArray = null;
    54  
    55    /**
    56      A list of keys for nanosecond timestamps that will be split into two properties: `separateNanos = ['Time']` will
    57      produce a `Time` property with a millisecond timestamp and `TimeNanos` with the nanoseconds alone.
    58  
    59      separateNanos = ['Time'];
    60      { Time: 1607839992000100000 } => { Time: 1607839992000, TimeNanos: 100096 }
    61  
    62      @property separateNanos
    63      @type String[]
    64     */
    65    separateNanos = null;
    66  
    67    keyForAttribute(attr) {
    68      return capitalize(camelize(attr));
    69    }
    70  
    71    keyForRelationship(attr, relationshipType) {
    72      const key = `${capitalize(camelize(singularize(attr)))}ID`;
    73      return relationshipType === 'hasMany' ? pluralize(key) : key;
    74    }
    75  
    76    // Modeled after the pushPayload for ember-data/serializers/rest
    77    pushPayload(store, payload) {
    78      const documentHash = {
    79        data: [],
    80        included: [],
    81      };
    82  
    83      Object.keys(payload).forEach((key) => {
    84        const modelName = this.modelNameFromPayloadKey(key);
    85        const serializer = store.serializerFor(modelName);
    86        const type = store.modelFor(modelName);
    87  
    88        makeArray(payload[key]).forEach((hash) => {
    89          const { data, included } = serializer.normalize(type, hash, key);
    90          documentHash.data.push(data);
    91          if (included) {
    92            documentHash.included.push(...included);
    93          }
    94        });
    95      });
    96  
    97      store.push(documentHash);
    98    }
    99  
   100    normalize(modelClass, hash) {
   101      if (hash) {
   102        if (this.arrayNullOverrides) {
   103          this.arrayNullOverrides.forEach((key) => {
   104            if (!hash[key]) {
   105              hash[key] = [];
   106            }
   107          });
   108        }
   109        if (this.objectNullOverrides) {
   110          this.objectNullOverrides.forEach((key) => {
   111            if (!hash[key]) {
   112              hash[key] = {};
   113            }
   114          });
   115        }
   116  
   117        if (this.mapToArray) {
   118          this.mapToArray.forEach((conversion) => {
   119            let apiKey, uiKey;
   120  
   121            if (conversion.beforeName) {
   122              apiKey = conversion.beforeName;
   123              uiKey = conversion.afterName;
   124            } else {
   125              apiKey = conversion;
   126              uiKey = conversion;
   127            }
   128  
   129            const map = hash[apiKey] || {};
   130  
   131            hash[uiKey] = Object.keys(map)
   132              .sort()
   133              .map((mapKey) => {
   134                const propertiesForKey = map[mapKey] || {};
   135                const convertedMap = { Name: mapKey };
   136  
   137                assign(convertedMap, propertiesForKey);
   138  
   139                return convertedMap;
   140              });
   141          });
   142        }
   143  
   144        if (this.separateNanos) {
   145          this.separateNanos.forEach((key) => {
   146            const timeWithNanos = hash[key];
   147            hash[`${key}Nanos`] = timeWithNanos % 1000000;
   148            hash[key] = Math.floor(timeWithNanos / 1000000);
   149          });
   150        }
   151      }
   152  
   153      return super.normalize(modelClass, hash);
   154    }
   155  
   156    normalizeFindAllResponse(store, modelClass) {
   157      const result = super.normalizeFindAllResponse(...arguments);
   158      this.cullStore(store, modelClass.modelName, result.data);
   159      return result;
   160    }
   161  
   162    // When records are removed server-side, and therefore don't show up in requests,
   163    // the local copies of those records need to be unloaded from the store.
   164    cullStore(store, type, records, storeFilter = () => true) {
   165      const newRecords = copy(records).filter((record) => get(record, 'id'));
   166      const oldRecords = store.peekAll(type);
   167      oldRecords
   168        .filter((record) => get(record, 'id'))
   169        .filter(storeFilter)
   170        .forEach((old) => {
   171          const newRecord = newRecords.find(
   172            (record) => get(record, 'id') === get(old, 'id')
   173          );
   174          if (!newRecord) {
   175            removeRecord(store, old);
   176          } else {
   177            newRecords.removeObject(newRecord);
   178          }
   179        });
   180    }
   181  
   182    modelNameFromPayloadKey(key) {
   183      return singularize(dasherize(key));
   184    }
   185  }