github.com/anth0d/nomad@v0.0.0-20221214183521-ae3a0a2cad06/ui/app/serializers/application.js (about)

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