UNPKG

5.13 kBJavaScriptView Raw
1import 'babel-core/register'
2import 'babel-polyfill'
3import Promise from 'bluebird'
4import _ from 'lodash'
5import inspect from 'object-inspect'
6import log from 'loglevel'
7
8const nodeArgs = require('node-args')
9
10// Add loglevel plugin to display inspected optional second parameter:
11const originalFactory = log.methodFactory
12log.methodFactory = function (methodName, logLevel, loggerName) {
13 const rawMethod = originalFactory(methodName, logLevel, loggerName)
14 return (message, optionalData = null) => {
15 let msg = message
16 if (optionalData) {
17 msg += ': ' + inspect(optionalData)
18 }
19 rawMethod(msg)
20 }
21}
22log.setLevel(log.getLevel()) // Be sure to call setLevel method in order to apply plugin
23export const logger = log
24
25// wrapper for kinvey-flex-sdk service method
26export const initFlexSdk = defineService => {
27 const sdk = require('kinvey-flex-sdk')
28 const opts = nodeArgs.port ? {port: nodeArgs.port} : null
29 sdk.service(opts, defineService)
30}
31
32export const getAsyncDataStore = (collectionName, modules) => {
33 const store = modules.dataStore()
34 const collection = store.collection(collectionName)
35 return Promise.promisifyAll(collection)
36}
37
38export const getAsyncUserStore = modules => {
39 const store = modules.userStore()
40 return Promise.promisifyAll(store)
41}
42
43export const setLowercaseFields = (data, fields) => {
44 if (_.isArray(fields) && _.isPlainObject(data)) {
45 const result = {...data}
46 _.forEach(fields, field => {
47 if (_.isString(data[field])) {
48 result[`${field}LC`] = _.toLower(data[field])
49 }
50 })
51 return result
52 }
53}
54
55export const findEntityById = (entityType, entityId, modules) => {
56 const store = entityType === 'user'
57 ? getAsyncUserStore(modules)
58 : getAsyncDataStore(entityType, modules)
59 return store.findByIdAsync(entityId)
60}
61
62/**
63 * Return a plain object containing the keys and values from newData that should be denormalized in another collection.
64 * @param {string} collectionName
65 * @param {object} newData
66 * @param {object} denormMap Keys of denormMap objects for each collection can be written in dot-notation, but not values. The values are top-level user fields for denormalization. For example, denormMap can be {org: {name: orgName, address.zip: orgZip}}
67 * @return {object}
68 */
69export const getPotentialDenormalizedData = ({collectionName, newData, denormMap}) => _.chain(denormMap)
70 .mapValues((val, key) => _.get(newData, key))
71 .pickBy(val => !_.isEmpty(val))
72 .value()
73
74/**
75 * Return a plain object containing the keys and values from potentialDenormalizedData that are different than in oldData.
76 * @param {object} oldData
77 * @param {object} potentialDenormalizedData
78 * @param {object} denormMap
79 * @return {object}
80 */
81export const getFinalDenormalizedData = ({oldData, potentialDenormalizedData, denormMap}) => _.chain(potentialDenormalizedData)
82 .pickBy((val, key) => val !== _.get(oldData, key)) // pick relevant values that are different from previously-saved
83 .mapKeys((val, key) => denormMap[key]) // change keys from source keys to target keys
84 .value()
85
86/**
87 * Return a plain object containing:
88 * oldData: the previously-saved collection data
89 * denormData: any fields in newData that are changing and are to be denormalized in other collections.
90 *
91 * @param {string} collectionName
92 * @param {object} newData
93 * @param {string} entityId
94 * @param {object} denormMap Keys of denormMap objects for each collection can be written in dot-notation, but not values. The values are top-level user fields for denormalization. For example, denormMap can be {org: {name: orgName, address.zip: orgZip}}
95 * @param {string} modules
96 * @returns {Promise<any>}
97 */
98export const getDenormalizedData = async ({collectionName, entityId, newData, denormMap, kinveyModules}) => {
99 const relevantData = getPotentialDenormalizedData({collectionName, newData, denormMap})
100 if (_.isEmpty(relevantData)) {
101 return null
102 }
103 const oldData = await findEntityById(collectionName, entityId, kinveyModules)
104 const denormData = getFinalDenormalizedData({oldData, relevantData, denormMap})
105 return {
106 oldData,
107 denormData: _.isEmpty(denormData) ? null : denormData
108 }
109}
110
111/**
112 * Methods for setting and deleting objects with unique "id" keys in an array of objects.
113 */
114export const entityList = {
115 findIndex: (arr, item) => _.findIndex(arr, existingItem => existingItem.id === item.id),
116 /**
117 * Add or update an object in an array.
118 * @param {array} arr
119 * @param {object} item Must have an "id" key set.
120 * @returns {any[]}
121 */
122 set: (arr = [], item) => {
123 const result = Array.from(arr)
124 const idx = entityList.findIndex(arr, item)
125 if (idx === -1) {
126 result.push(item)
127 } else {
128 result.splice(idx, 1, item)
129 }
130 return result
131 },
132 /**
133 * Remove an object from an array.
134 * @param {array} arr
135 * @param {object} item Must have an "id" key set.
136 * @returns {any[]}
137 */
138 del: (arr = [], item) => {
139 const result = Array.from(arr)
140 const idx = entityList.findIndex(arr, item)
141 if (idx !== -1) {
142 result.splice(idx, 1)
143 }
144 return result
145 }
146}