github.com/Ilhicas/nomad@v1.0.4-0.20210304152020-e86851182bc3/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 9 export default class Application extends JSONSerializer { 10 primaryKey = 'ID'; 11 12 /** 13 A list of keys that are converted to empty arrays if their value is null. 14 15 arrayNullOverrides = ['Array']; 16 { Array: null } => { Array: [] } 17 18 @property arrayNullOverrides 19 @type String[] 20 */ 21 arrayNullOverrides = null; 22 23 /** 24 A list of keys that are converted to empty objects if their value is null. 25 26 objectNullOverrides = ['Object']; 27 { Object: null } => { Object: {} } 28 29 @property objectNullOverrides 30 @type String[] 31 */ 32 objectNullOverrides = null; 33 34 /** 35 A list of keys or objects to convert a map into an array of maps with the original map keys as Name properties. 36 37 mapToArray = ['Map']; 38 { Map: { a: { x: 1 } } } => { Map: [ { Name: 'a', x: 1 }] } 39 40 mapToArray = [{ beforeName: 'M', afterName: 'Map' }]; 41 { M: { a: { x: 1 } } } => { Map: [ { Name: 'a', x: 1 }] } 42 43 @property mapToArray 44 @type (String|Object)[] 45 */ 46 mapToArray = null; 47 48 /** 49 A list of keys for nanosecond timestamps that will be split into two properties: `separateNanos = ['Time']` will 50 produce a `Time` property with a millisecond timestamp and `TimeNanos` with the nanoseconds alone. 51 52 separateNanos = ['Time']; 53 { Time: 1607839992000100000 } => { Time: 1607839992000, TimeNanos: 100096 } 54 55 @property separateNanos 56 @type String[] 57 */ 58 separateNanos = null; 59 60 keyForAttribute(attr) { 61 return attr.camelize().capitalize(); 62 } 63 64 keyForRelationship(attr, relationshipType) { 65 const key = `${singularize(attr) 66 .camelize() 67 .capitalize()}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(record => get(record, 'id') === get(old, 'id')); 167 if (!newRecord) { 168 removeRecord(store, old); 169 } else { 170 newRecords.removeObject(newRecord); 171 } 172 }); 173 } 174 175 modelNameFromPayloadKey(key) { 176 return singularize(key.dasherize()); 177 } 178 }