@rentman/rm-core 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (68) hide show
  1. package/.editorconfig +23 -0
  2. package/package.json +33 -0
  3. package/src/classes/ApiFormatter.ts +338 -0
  4. package/src/classes/BatchStatus.ts +86 -0
  5. package/src/classes/ChangesCompiler.ts +161 -0
  6. package/src/classes/ChangesProcessor.ts +475 -0
  7. package/src/classes/CollectionCache.ts +234 -0
  8. package/src/classes/CollectionEntryService.ts +83 -0
  9. package/src/classes/CollectionHandler.ts +619 -0
  10. package/src/classes/CollectionResourceService.ts +38 -0
  11. package/src/classes/ColumnCache.ts +114 -0
  12. package/src/classes/ColumnExpansion.ts +74 -0
  13. package/src/classes/ColumnHandler.ts +90 -0
  14. package/src/classes/ColumnSet.ts +181 -0
  15. package/src/classes/ColumnUtil.ts +589 -0
  16. package/src/classes/CreateRequest.ts +158 -0
  17. package/src/classes/ItemAdministrator.ts +571 -0
  18. package/src/classes/ItemCache.ts +158 -0
  19. package/src/classes/ItemEntryService.ts +488 -0
  20. package/src/classes/ItemHandler.ts +592 -0
  21. package/src/classes/ItemRequestService.ts +229 -0
  22. package/src/classes/ItemResourceService.ts +36 -0
  23. package/src/classes/KeyService.ts +76 -0
  24. package/src/classes/LockService.ts +184 -0
  25. package/src/classes/ModuleChangesCompiler.ts +123 -0
  26. package/src/classes/PromiseService.ts +19 -0
  27. package/src/classes/QueryMatcher.ts +135 -0
  28. package/src/classes/QueryParser.ts +209 -0
  29. package/src/classes/QueryService.ts +35 -0
  30. package/src/classes/RequestColumnExpansion.ts +31 -0
  31. package/src/classes/ResourceCache.ts +289 -0
  32. package/src/classes/Util.ts +422 -0
  33. package/src/constants.ts +11 -0
  34. package/src/factories/BatchStatusFactory.ts +18 -0
  35. package/src/factories/ChangesCompilerFactory.ts +20 -0
  36. package/src/factories/ChangesProcessorFactory.ts +53 -0
  37. package/src/factories/CollectionCacheFactory.ts +15 -0
  38. package/src/factories/CollectionEntryFactory.ts +35 -0
  39. package/src/factories/CollectionResourceFactory.ts +36 -0
  40. package/src/factories/ColumnExpansionFactory.ts +25 -0
  41. package/src/factories/ColumnSetFactory.ts +24 -0
  42. package/src/factories/CreateRequestFactory.ts +28 -0
  43. package/src/factories/ItemCacheFactory.ts +18 -0
  44. package/src/factories/ItemEntryFactory.ts +18 -0
  45. package/src/factories/ItemResourceFactory.ts +28 -0
  46. package/src/factories/ModuleChangesCompilerFactory.ts +21 -0
  47. package/src/factories/QueryMatcherFactory.ts +20 -0
  48. package/src/factories/QueryParserFactory.ts +10 -0
  49. package/src/factories/RequestColumnExpansionFactory.ts +15 -0
  50. package/src/factories/ResourceCacheFactory.ts +55 -0
  51. package/src/index.ts +188 -0
  52. package/src/interfaces/ApiRequestServiceInterface.ts +17 -0
  53. package/src/interfaces/AuthInterface.ts +5 -0
  54. package/src/interfaces/ErrorHandlerInterface.ts +3 -0
  55. package/src/interfaces/ResourceCacheInterface.ts +9 -0
  56. package/src/models/CollectionEditResource.ts +139 -0
  57. package/src/models/CollectionEntry.ts +448 -0
  58. package/src/models/CollectionResource.ts +223 -0
  59. package/src/models/CollectionViewResource.ts +23 -0
  60. package/src/models/EditResource.ts +15 -0
  61. package/src/models/ItemEntry.ts +24 -0
  62. package/src/models/ItemResource.ts +35 -0
  63. package/src/models/ViewResource.ts +14 -0
  64. package/tsconfig.json +12 -0
  65. package/tslint.json +63 -0
  66. package/webpack.common.js +35 -0
  67. package/webpack.dev.js +10 -0
  68. package/webpack.prod.js +17 -0
@@ -0,0 +1,229 @@
1
+ import ColumnExpansionFactory from "../factories/ColumnExpansionFactory";
2
+ import ColumnSetFactory from "../factories/ColumnSetFactory";
3
+ import ApiRequestServiceInterface from '../interfaces/ApiRequestServiceInterface';
4
+ import ErrorHandlerInterface from '../interfaces/ErrorHandlerInterface';
5
+ import CollectionEntry from "../models/CollectionEntry";
6
+ import ItemEntry from "../models/ItemEntry";
7
+ import ColumnExpansion from "./ColumnExpansion";
8
+ import ColumnHandler from "./ColumnHandler";
9
+ import ItemEntryService from "./ItemEntryService";
10
+ import ItemHandler from "./ItemHandler";
11
+ import PromiseService from "./PromiseService";
12
+ import QueryService from "./QueryService";
13
+
14
+ import { pathExists } from "./Util";
15
+
16
+ export default class ItemRequestService {
17
+ constructor (
18
+ private apiRequestService: ApiRequestServiceInterface,
19
+ private errorHandler: ErrorHandlerInterface,
20
+ private itemHandler: ItemHandler,
21
+ private columnHandler: ColumnHandler,
22
+ private columnExpansionFactory: ColumnExpansionFactory,
23
+ private columnSetFactory: ColumnSetFactory,
24
+ private itemEntryService: ItemEntryService,
25
+ private queryService: QueryService,
26
+ private promiseService: PromiseService
27
+ ) {
28
+ }
29
+
30
+ requestItem (itemType, itemId, columns) {
31
+ const requestColumns = {
32
+ [itemType]: columns
33
+ };
34
+
35
+ return this.apiRequestService.query(
36
+ itemType,
37
+ {id: itemId},
38
+ requestColumns
39
+ );
40
+ }
41
+
42
+ requestItems (collectionEntry: CollectionEntry, query = collectionEntry.query.object, columns = collectionEntry.options.columns) {
43
+ const options = collectionEntry.options;
44
+
45
+ const requestColumns = {
46
+ [collectionEntry.itemType]: columns
47
+ };
48
+
49
+ const params = {
50
+ requestType: 'query',
51
+ columns: requestColumns,
52
+ query: query,
53
+ itemType: '',
54
+ allLinkIds: false,
55
+ limit: null
56
+ };
57
+
58
+ if (options.queryItemType === null)
59
+ params.itemType = collectionEntry.itemType;
60
+ else {
61
+ params.itemType = options.queryItemType;
62
+ params.allLinkIds = true;
63
+ }
64
+
65
+ if (options.limit !== null)
66
+ params.limit = options.limit;
67
+
68
+ return this.apiRequestService.requestSkeleton(params);
69
+ }
70
+
71
+ requestLinkItems (parentType, parentIdArray, itemType, query, columns): Promise<any> {
72
+ const requestColumns = {
73
+ [itemType]: columns
74
+ };
75
+
76
+ return query === null ?
77
+ this.apiRequestService.query(
78
+ parentType,
79
+ {id: parentIdArray},
80
+ requestColumns
81
+ ) :
82
+ this.apiRequestService.query(
83
+ itemType,
84
+ this.queryService.addAndCondition(
85
+ query,
86
+ {linkedTo: parentType, query: {id: parentIdArray}}
87
+ ),
88
+ requestColumns // should contain a derived column that refers to the parent
89
+ );
90
+ }
91
+
92
+ processExpansion (requestColumns, response, itemType: string, itemEntries: ItemEntry[]) {
93
+ const columnExpansion = this.columnExpansionFactory.construct(
94
+ itemType,
95
+ requestColumns,
96
+ response.fetchColumnsObject()
97
+ );
98
+
99
+ for (const itemEntry of itemEntries) {
100
+ if (this.itemEntryService.isLocal(itemEntry))
101
+ continue;
102
+
103
+ this.handleCachedItem(
104
+ itemEntry,
105
+ response,
106
+ columnExpansion
107
+ );
108
+ }
109
+
110
+ return columnExpansion;
111
+ }
112
+
113
+ processResponse (response, idArray, parent, columnInfo, columnExpansion?): Promise<ItemEntry[]> {
114
+ if (columnExpansion === undefined)
115
+ columnExpansion = this.columnExpansionFactory.construct(
116
+ columnInfo.itemType,
117
+ columnInfo.true ? true : columnInfo.request,
118
+ columnInfo.response
119
+ );
120
+
121
+ const itemType = columnInfo.itemType;
122
+ const rootColumns = columnInfo.root;
123
+ const itemEntries = [];
124
+ const deferredEntries = [];
125
+
126
+ // should be fast...
127
+ for (const itemId of idArray) {
128
+ let itemEntry = this.itemHandler.entries.get(itemType, itemId);
129
+
130
+ if (itemEntry === undefined) {
131
+ itemEntry = this.itemHandler.createEntry(
132
+ itemId,
133
+ response.fetchObject(itemType, itemId),
134
+ response.fetchDerivedObject(itemType, itemId, rootColumns),
135
+ columnInfo
136
+ );
137
+ itemEntries.push(itemEntry);
138
+ } else {
139
+ if (itemEntry.deferred !== undefined) {
140
+ if (itemEntry.deferRequest) {
141
+ itemEntries.push(
142
+ this.itemHandler.resolveDeferredEntry(
143
+ itemEntry,
144
+ response.fetchObject(itemType, itemId),
145
+ response.fetchDerivedObject(itemType, itemId, rootColumns),
146
+ columnInfo
147
+ )
148
+ );
149
+ } else
150
+ deferredEntries.push(itemEntry.deferred.promise);
151
+ } else {
152
+ itemEntries.push(
153
+ this.handleCachedItem(
154
+ itemEntry,
155
+ response,
156
+ columnExpansion
157
+ )
158
+ );
159
+ }
160
+ }
161
+
162
+ if (parent !== null)
163
+ itemEntry.parent = parent;
164
+ }
165
+
166
+ return this.promiseService.all(deferredEntries).then(
167
+ resolvedEntries => {
168
+ for (const resolvedEntry of resolvedEntries)
169
+ itemEntries.push(
170
+ this.handleCachedItem(
171
+ resolvedEntry,
172
+ response,
173
+ columnExpansion
174
+ )
175
+ );
176
+
177
+ return itemEntries;
178
+ },
179
+ this.errorHandler.reject
180
+ );
181
+ }
182
+
183
+ handleCachedItem (itemEntry, response, columnExpansion: ColumnExpansion) {
184
+ const expansionResult = columnExpansion.run(itemEntry.columns, true);
185
+
186
+ return expansionResult === null ?
187
+ itemEntry :
188
+ this.itemEntryService.expand(
189
+ itemEntry,
190
+ response.fetchObject(itemEntry.itemType, itemEntry.itemId),
191
+ response.fetchDerivedObject(
192
+ itemEntry.itemType,
193
+ itemEntry.itemId,
194
+ expansionResult.difference.root
195
+ ),
196
+ expansionResult
197
+ );
198
+ }
199
+
200
+ processLinkResponse (response, parentType, parentIdArray, itemType, options) {
201
+ const responseColumns = response.fetchColumnsObject();
202
+ const columnInfo = this.columnSetFactory.construct(itemType, options.columns, responseColumns);
203
+ const columnExpansion = this.columnExpansionFactory.construct(itemType, options.columns, responseColumns);
204
+ const parentItems = response.items[parentType];
205
+ const promises = {};
206
+
207
+ for (const parentId of parentIdArray) {
208
+ promises[parentId] = pathExists(parentItems, [parentId, 'links', itemType]) ?
209
+ this.processResponse(
210
+ response,
211
+ parentItems[parentId].links[itemType],
212
+ {itemType: parentType, itemId: parentId},
213
+ columnInfo,
214
+ columnExpansion.run
215
+ ) :
216
+ [];
217
+ }
218
+
219
+ return this.promiseService.all(promises).then(resolved => {
220
+ return {
221
+ items: resolved,
222
+ columns: columnInfo,
223
+ columnExpansion: columnExpansion.run
224
+ };
225
+ },
226
+ this.errorHandler.reject
227
+ );
228
+ }
229
+ }
@@ -0,0 +1,36 @@
1
+ import { noop } from '../index';
2
+ import ItemEntryService from "./ItemEntryService";
3
+ import { shallowMerge } from "./Util";
4
+
5
+ export default class ItemResourceService {
6
+ constructor (
7
+ private itemEntryService: ItemEntryService
8
+ ) {
9
+
10
+ }
11
+
12
+ processOptions (options) {
13
+ return shallowMerge(
14
+ options,
15
+ {
16
+ edit: false,
17
+ onChange: noop,
18
+ onDeactivate: noop
19
+ }
20
+ );
21
+ }
22
+
23
+ compareOptions (first, second) {
24
+ for (const key in first) {
25
+ if (first[key] !== second[key])
26
+ return false;
27
+ }
28
+
29
+ return true;
30
+ }
31
+
32
+ isNew (resource) {
33
+ return this.itemEntryService.isLocal(resource.entry) &&
34
+ resource.transactions === undefined;
35
+ }
36
+ }
@@ -0,0 +1,76 @@
1
+ export default class KeyService {
2
+ NEW_PREFIX: string = '-1';
3
+ DUPLICATE_PREFIX: string = '-2';
4
+
5
+ NEW_KEYWORD: string = 'new-';
6
+ DUPLICATE_KEYWORD: string = 'dup-';
7
+
8
+ seperator: string = ':';
9
+
10
+ constructor () {
11
+ }
12
+
13
+ getSingleKey (itemType: string, itemId: number | string) {
14
+ return itemType.concat(this.seperator, String(itemId));
15
+ }
16
+
17
+ getCollectionCacheKey (parentType: string, parentId: number, childType: string) {
18
+ return parentType.concat(this.seperator, String(parentId), this.seperator, childType);
19
+ }
20
+
21
+ getCssKey () {
22
+ return Array.prototype.join.call(arguments, '_');
23
+ }
24
+
25
+ parseStateKey (stateKey: string) {
26
+ stateKey = stateKey.toString();
27
+
28
+ if (stateKey.indexOf(this.NEW_KEYWORD) === 0)
29
+ return {
30
+ type: 'new',
31
+ template: stateKey.substring(this.NEW_KEYWORD.length)
32
+ };
33
+
34
+ if (stateKey.indexOf(this.DUPLICATE_KEYWORD) === 0)
35
+ return {
36
+ type: 'duplicate',
37
+ itemId: stateKey.substring(this.DUPLICATE_KEYWORD.length)
38
+ };
39
+
40
+ return null;
41
+ }
42
+
43
+ getDuplicateStateKey (itemId: string | number) {
44
+ return this.DUPLICATE_KEYWORD.concat(String(itemId));
45
+ }
46
+
47
+ getNewStateKey (templateType: string) {
48
+ return this.NEW_KEYWORD.concat(templateType);
49
+ }
50
+
51
+ getLocalId (): number {
52
+ return parseInt(this.NEW_PREFIX.concat(this.getRandomString()), 10);
53
+ }
54
+
55
+ getLocalDuplicateId (): number {
56
+ return parseInt(this.DUPLICATE_PREFIX.concat(this.getRandomString()), 10);
57
+ }
58
+
59
+ getRandomString () {
60
+ return Math.random().toString().split('.')[1].substr(0, 8);
61
+ }
62
+
63
+ // note: the changes compiler uses this
64
+ // might be called with undefined (itemHandler.createRequest)
65
+ isLocalId (itemId: number | string) {
66
+ return itemId !== undefined && this.isNewId(itemId) || this.isDuplicateId(itemId);
67
+ }
68
+
69
+ isNewId (itemId: number | string) {
70
+ return itemId.toString().indexOf(this.NEW_PREFIX) === 0 || itemId === this.NEW_KEYWORD;
71
+ }
72
+
73
+ isDuplicateId (itemId: number | string) {
74
+ return itemId.toString().indexOf(this.DUPLICATE_PREFIX) === 0 || itemId === this.DUPLICATE_KEYWORD;
75
+ }
76
+ }
@@ -0,0 +1,184 @@
1
+ import ApiRequestServiceInterface from '../interfaces/ApiRequestServiceInterface';
2
+ import ErrorHandlerInterface from '../interfaces/ErrorHandlerInterface';
3
+ import ItemEntry from "../models/ItemEntry";
4
+ import KeyService from "./KeyService";
5
+ import PromiseService from "./PromiseService";
6
+ import { createPath } from "./Util";
7
+
8
+ export default class LockService {
9
+ lockItems = {};
10
+ promises = {};
11
+
12
+ constructor (
13
+ private apiRequestService: ApiRequestServiceInterface,
14
+ private errorHandler: ErrorHandlerInterface,
15
+ private keyService: KeyService,
16
+ private promiseService: PromiseService
17
+ ) {
18
+
19
+ }
20
+
21
+ getValue (itemEntry: ItemEntry, map) {
22
+ const itemType = itemEntry.itemType;
23
+
24
+ if (map[itemType] === undefined)
25
+ return undefined;
26
+
27
+ return map[itemType][itemEntry.itemId];
28
+ }
29
+
30
+ setValue (itemEntry: ItemEntry, value, map) {
31
+ return createPath(
32
+ map,
33
+ [itemEntry.itemType, itemEntry.itemId],
34
+ [{}, value]
35
+ );
36
+ }
37
+
38
+ getLocks () {
39
+ return this.lockItems;
40
+ }
41
+
42
+ hasLock (lockTokenId) {
43
+ for (const itemType in this.lockItems) {
44
+ for (const itemId in this.lockItems[itemType]) {
45
+ const lockItem = this.lockItems[itemType][itemId];
46
+
47
+ // tslint:disable:triple-equals
48
+ if (!lockItem.isForeign && lockItem.id == lockTokenId)
49
+ return true;
50
+ }
51
+ }
52
+
53
+ return false;
54
+ }
55
+
56
+ // should be fast (watched)
57
+ isLocked (itemEntry: ItemEntry) {
58
+ const lockItem = this.getValue(itemEntry, this.lockItems);
59
+
60
+ if (lockItem === undefined)
61
+ return false;
62
+
63
+ return lockItem.isForeign;
64
+ }
65
+
66
+ getMessage (itemEntry) {
67
+ const lockItem = this.getValue(itemEntry, this.lockItems);
68
+
69
+ if (lockItem === undefined)
70
+ return undefined;
71
+
72
+ if (!lockItem.isForeign)
73
+ return undefined;
74
+
75
+ return lockItem.message;
76
+ }
77
+
78
+ // does not reject when a foreign lock is encountered
79
+ // is also used by deleteLock
80
+ fetchCachedLock (itemEntry: ItemEntry) {
81
+ const lock = this.getValue(itemEntry, this.lockItems);
82
+
83
+ if (lock !== undefined)
84
+ return this.promiseService.when(lock);
85
+
86
+ const promise = this.getValue(itemEntry, this.promises);
87
+
88
+ if (promise !== undefined)
89
+ return promise;
90
+
91
+ return this.promiseService.when();
92
+ }
93
+
94
+ fetchLock (itemEntry: ItemEntry) {
95
+ return this.fetchCachedLock(itemEntry).then(lockItem => {
96
+ if (lockItem !== undefined)
97
+ return lockItem;
98
+
99
+ return this.requestLock(itemEntry);
100
+ },
101
+ this.errorHandler.reject
102
+ ).then(lockItem => {
103
+ return lockItem.isForeign ?
104
+ this.errorHandler.reject(lockItem.message) :
105
+ lockItem.token;
106
+ },
107
+ this.errorHandler.reject
108
+ );
109
+ }
110
+
111
+ requestLock (itemEntry: ItemEntry) {
112
+ const itemType = itemEntry.itemType;
113
+ const itemId = itemEntry.itemId;
114
+
115
+ const promise = this.apiRequestService.create(
116
+ 'Locktoken',
117
+ this.keyService.getLocalId(),
118
+ {itemtype: itemType, item: itemId}
119
+ ).then(
120
+ response => {
121
+ delete this.promises[itemType][itemId];
122
+
123
+ return this.setValue(
124
+ itemEntry,
125
+ response.fetchObject(
126
+ 'Locktoken',
127
+ response.links.Locktoken[0]
128
+ ),
129
+ this.lockItems
130
+ );
131
+ }, error => {
132
+ delete this.promises[itemType][itemId];
133
+
134
+ if (error.code === 301) {
135
+ return this.setValue(
136
+ itemEntry,
137
+ {
138
+ isForeign: true,
139
+ message: error.message
140
+ },
141
+ this.lockItems
142
+ );
143
+ }
144
+
145
+ return this.errorHandler.reject(error);
146
+ }
147
+ );
148
+
149
+ return this.setValue(itemEntry, promise, this.promises);
150
+ }
151
+
152
+ deleteLock (itemEntry) {
153
+ return this.fetchCachedLock(itemEntry).then(cachedLock => {
154
+ // undefined: not requested yet
155
+
156
+ if (cachedLock === undefined)
157
+ return;
158
+
159
+ if (cachedLock.isForeign) {
160
+ this.clearLock(itemEntry);
161
+ return;
162
+ }
163
+
164
+ return this.apiRequestService.delete('Locktoken', cachedLock.id)
165
+ .then(
166
+ () => {
167
+ this.clearLock(itemEntry);
168
+ },
169
+ this.errorHandler.reject
170
+ );
171
+ },
172
+ this.errorHandler.reject
173
+ );
174
+ }
175
+
176
+ clearLock (itemEntry) {
177
+ const itemType = itemEntry.itemType;
178
+
179
+ if (this.lockItems[itemType] === undefined)
180
+ return false;
181
+
182
+ return delete this.lockItems[itemType][itemEntry.itemId];
183
+ }
184
+ }
@@ -0,0 +1,123 @@
1
+ import ItemEntry from "../models/ItemEntry";
2
+ import CollectionCache from "./CollectionCache";
3
+ import ItemCache from "./ItemCache";
4
+ import ItemEntryService from "./ItemEntryService";
5
+ import { hasProperties } from "./Util";
6
+
7
+ const EMPTY_ENTRY = {};
8
+
9
+ export default class ModuleChangesCompiler {
10
+ parentMap;
11
+ destination;
12
+
13
+ constructor (
14
+ private itemEntryService: ItemEntryService,
15
+ private rootItemEntry: ItemEntry,
16
+ private singleItemCache: ItemCache,
17
+ private collectionCache: CollectionCache
18
+ ) {
19
+ }
20
+
21
+ process () {
22
+ this.parentMap = this.createParentMap(this.singleItemCache);
23
+ this.processItems(this.rootItemEntry.itemType, [this.rootItemEntry], {});
24
+ }
25
+
26
+ private createParentMap (itemCache) {
27
+ const result = {};
28
+
29
+ itemCache.forEach(itemEntry => {
30
+ const itemType = itemEntry.itemType;
31
+ const parent = itemEntry.parent;
32
+
33
+ if (parent === undefined) // we don't care for items that are not linked to the root item
34
+ return;
35
+
36
+ const parentType = parent.itemType;
37
+ const parentId = parent.itemId;
38
+
39
+ if (result[parentType] === undefined)
40
+ result[parentType] = {};
41
+
42
+ let mapEntry = result[parentType];
43
+
44
+ if (mapEntry[parentId] === undefined)
45
+ mapEntry[parentId] = {};
46
+
47
+ mapEntry = mapEntry[parentId];
48
+
49
+ if (mapEntry[itemType] === undefined)
50
+ mapEntry[itemType] = [];
51
+
52
+ mapEntry[itemType].push(itemEntry);
53
+ }
54
+ );
55
+
56
+ return result;
57
+ }
58
+
59
+ private processItems (itemType, itemEntries: ItemEntry[], linkAccumulator) {
60
+ if (this.destination[itemType] === undefined)
61
+ this.destination[itemType] = {};
62
+
63
+ if (linkAccumulator[itemType] === undefined)
64
+ linkAccumulator[itemType] = [];
65
+
66
+ for (const itemEntry of itemEntries) {
67
+ const itemId = itemEntry.itemId;
68
+
69
+ // each item only has a single parent, so we can safely do this
70
+ if (this.destination[itemType][itemId] !== undefined)
71
+ continue;
72
+
73
+ linkAccumulator[itemType].push(itemId);
74
+
75
+ this.destination[itemType][itemId] = this.processItem(itemEntry);
76
+ }
77
+ }
78
+
79
+ private processItem (itemEntry) {
80
+ const itemType = itemEntry.itemType;
81
+ const itemId = itemEntry.itemId;
82
+ const childItems = this.getItemsByParent(itemType, itemId);
83
+ const childCollections = this.collectionCache.getCollectionsByParent(itemType, itemId);
84
+ const values = this.itemEntryService.formatRequest(itemEntry);
85
+ const links = {};
86
+
87
+ for (const childType in childItems)
88
+ this.processItems(childType, childItems[childType], links);
89
+
90
+ for (const collectionEntry of childCollections) {
91
+ if (collectionEntry.options.query !== null)
92
+ continue;
93
+
94
+ this.processItems(collectionEntry.itemType, collectionEntry.items, links);
95
+ }
96
+
97
+ const hasValues = hasProperties(values);
98
+ const hasLinks = hasProperties(links);
99
+
100
+ if (hasValues && hasLinks)
101
+ return {values: values, links: links};
102
+
103
+ if (hasValues)
104
+ return {values: values};
105
+
106
+ if (hasLinks)
107
+ return {links: links};
108
+
109
+ return EMPTY_ENTRY;
110
+ }
111
+
112
+ private getItemsByParent (parentType, parentId) {
113
+ const mapEntry = this.parentMap[parentType];
114
+
115
+ if (mapEntry === undefined)
116
+ return {};
117
+
118
+ if (mapEntry[parentId] === undefined)
119
+ return {};
120
+
121
+ return mapEntry[parentId];
122
+ }
123
+ }
@@ -0,0 +1,19 @@
1
+ import { all, defer, reject, when } from 'q';
2
+
3
+ export default class PromiseService {
4
+ all (iterable): Promise<any> {
5
+ return all(iterable);
6
+ }
7
+
8
+ when (value?): Promise<any> {
9
+ return when(value);
10
+ }
11
+
12
+ reject (value?): Promise<any> {
13
+ return reject(value);
14
+ }
15
+
16
+ defer (): { resolve (value?); reject (value?); promise: Promise<any>; } {
17
+ return defer();
18
+ }
19
+ }