meadow-endpoints 3.0.7 → 4.0.2

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 (127) hide show
  1. package/Dockerfile_LUXURYCode +1 -1
  2. package/README.md +48 -14
  3. package/debug/Animal.json +62 -0
  4. package/debug/Harness-Configuration.json +31 -0
  5. package/debug/Harness.js +7 -108
  6. package/debug/KillHarness.sh +10 -0
  7. package/dist/meadowendpoints.js +4402 -0
  8. package/dist/meadowendpoints.min.js +92 -0
  9. package/dist/meadowendpoints.min.js.map +1 -0
  10. package/gulpfile.js +83 -0
  11. package/package.json +27 -15
  12. package/source/Meadow-Endpoints-Browser-Shim.js +14 -0
  13. package/source/Meadow-Endpoints.js +176 -565
  14. package/source/controller/Meadow-Endpoints-Controller-Base.js +161 -0
  15. package/source/controller/components/Meadow-Endpoints-Controller-BehaviorInjection.js +125 -0
  16. package/source/controller/components/Meadow-Endpoints-Controller-Error-StatusCodes.txt +189 -0
  17. package/source/controller/components/Meadow-Endpoints-Controller-Error.js +118 -0
  18. package/source/controller/components/Meadow-Endpoints-Controller-Log.js +103 -0
  19. package/source/controller/utility/Meadow-Endpoints-Filter-Parser.js +225 -0
  20. package/source/controller/utility/Meadow-Endpoints-Session-Marshaler.js +48 -0
  21. package/source/controller/utility/Meadow-Endpoints-Stream-RecordArray.js +66 -0
  22. package/source/endpoints/count/Meadow-Endpoint-Count.js +49 -0
  23. package/source/endpoints/count/Meadow-Endpoint-CountBy.js +40 -0
  24. package/source/endpoints/create/Meadow-Endpoint-BulkCreate.js +53 -0
  25. package/source/endpoints/create/Meadow-Endpoint-Create.js +58 -0
  26. package/source/endpoints/create/Meadow-Operation-Create.js +83 -0
  27. package/source/endpoints/delete/Meadow-Endpoint-Delete.js +93 -0
  28. package/source/endpoints/delete/Meadow-Endpoint-Undelete.js +108 -0
  29. package/source/endpoints/read/Meadow-Endpoint-Read.js +72 -0
  30. package/source/endpoints/read/Meadow-Endpoint-ReadDistinctList.js +92 -0
  31. package/source/endpoints/read/Meadow-Endpoint-ReadLiteList.js +85 -0
  32. package/source/endpoints/read/Meadow-Endpoint-ReadMax.js +55 -0
  33. package/source/endpoints/read/Meadow-Endpoint-ReadSelectList.js +89 -0
  34. package/source/endpoints/read/Meadow-Endpoint-Reads.js +75 -0
  35. package/source/endpoints/read/Meadow-Endpoint-ReadsBy.js +100 -0
  36. package/source/{crud → endpoints/read}/Meadow-Marshal-DistinctList.js +4 -13
  37. package/source/{crud → endpoints/read}/Meadow-Marshal-LiteList.js +5 -14
  38. package/source/endpoints/schema/Meadow-Endpoint-New.js +36 -0
  39. package/source/endpoints/schema/Meadow-Endpoint-Schema.js +36 -0
  40. package/source/endpoints/schema/Meadow-Endpoint-Validate.js +41 -0
  41. package/source/endpoints/update/Meadow-Endpoint-BulkUpdate.js +50 -0
  42. package/source/endpoints/update/Meadow-Endpoint-Update.js +58 -0
  43. package/source/endpoints/update/Meadow-Operation-Update.js +115 -0
  44. package/source/endpoints/upsert/Meadow-Endpoint-BulkUpsert.js +52 -0
  45. package/source/endpoints/upsert/Meadow-Endpoint-Upsert.js +57 -0
  46. package/source/endpoints/upsert/Meadow-Operation-Upsert.js +137 -0
  47. package/test/MeadowEndpoints_basic_tests.js +50 -2408
  48. package/test_support/bookstore-api-endpoint-exercises.paw +0 -0
  49. package/test_support/bookstore-configuration.json +28 -0
  50. package/test_support/bookstore-import-books-run.js +1 -0
  51. package/test_support/bookstore-import-books.js +215 -0
  52. package/test_support/bookstore-serve-meadow-endpoint-apis-IPC.js +138 -0
  53. package/test_support/bookstore-serve-meadow-endpoint-apis-run.js +6 -0
  54. package/test_support/bookstore-serve-meadow-endpoint-apis.js +129 -0
  55. package/test_support/data/books.csv +10001 -0
  56. package/test_support/model/ddl/BookStore.ddl +66 -0
  57. package/test_support/model/generated_diagram/README.md +1 -0
  58. package/test_support/model/generated_diagram/Stricture_Output.dot +13 -0
  59. package/test_support/model/generated_diagram/Stricture_Output.png +0 -0
  60. package/test_support/model/generated_documentation/Dictionary.md +18 -0
  61. package/test_support/model/generated_documentation/Model-Author.md +20 -0
  62. package/test_support/model/generated_documentation/Model-Book.md +26 -0
  63. package/test_support/model/generated_documentation/Model-BookAuthorJoin.md +14 -0
  64. package/test_support/model/generated_documentation/Model-BookPrice.md +25 -0
  65. package/test_support/model/generated_documentation/Model-Review.md +22 -0
  66. package/test_support/model/generated_documentation/ModelChangeTracking.md +17 -0
  67. package/test_support/model/generated_documentation/README.md +1 -0
  68. package/test_support/model/manual_scripts/DropTables.sql +5 -0
  69. package/test_support/model/manual_scripts/README.md +2 -0
  70. package/test_support/model/sql_create/BookStore-CreateDatabase.mysql.sql +116 -0
  71. package/test_support/model/sql_create/README.md +1 -0
  72. package/test_support/test_old/Tests.js +3243 -0
  73. package/test_support/test_old/untitled.js +88 -0
  74. package/source/Meadow-Authenticator.js +0 -31
  75. package/source/Meadow-Authorizers.js +0 -214
  76. package/source/Meadow-BehaviorModifications.js +0 -170
  77. package/source/Meadow-CommonServices.js +0 -206
  78. package/source/Meadow-MarshallSessionData.js +0 -64
  79. package/source/Restify-RouteParser.js +0 -114
  80. package/source/authorizers/Meadow-Authorizer-Allow.js +0 -17
  81. package/source/authorizers/Meadow-Authorizer-Deny.js +0 -17
  82. package/source/authorizers/Meadow-Authorizer-Mine.js +0 -47
  83. package/source/authorizers/Meadow-Authorizer-MyCustomer.js +0 -48
  84. package/source/crud/Meadow-Endpoint-BulkCreate.js +0 -67
  85. package/source/crud/Meadow-Endpoint-BulkUpdate.js +0 -74
  86. package/source/crud/Meadow-Endpoint-BulkUpsert.js +0 -76
  87. package/source/crud/Meadow-Endpoint-Count.js +0 -93
  88. package/source/crud/Meadow-Endpoint-CountBy.js +0 -101
  89. package/source/crud/Meadow-Endpoint-Create.js +0 -77
  90. package/source/crud/Meadow-Endpoint-Delete.js +0 -139
  91. package/source/crud/Meadow-Endpoint-Read.js +0 -109
  92. package/source/crud/Meadow-Endpoint-ReadDistinctList.js +0 -146
  93. package/source/crud/Meadow-Endpoint-ReadLiteList.js +0 -139
  94. package/source/crud/Meadow-Endpoint-ReadMax.js +0 -86
  95. package/source/crud/Meadow-Endpoint-ReadSelectList.js +0 -145
  96. package/source/crud/Meadow-Endpoint-Reads.js +0 -129
  97. package/source/crud/Meadow-Endpoint-ReadsBy.js +0 -155
  98. package/source/crud/Meadow-Endpoint-Undelete.js +0 -161
  99. package/source/crud/Meadow-Endpoint-Update.js +0 -80
  100. package/source/crud/Meadow-Endpoint-Upsert.js +0 -78
  101. package/source/crud/Meadow-Operation-Create.js +0 -105
  102. package/source/crud/Meadow-Operation-Update.js +0 -145
  103. package/source/crud/Meadow-Operation-Upsert.js +0 -106
  104. package/source/crud/Meadow-StreamRecordArray.js +0 -45
  105. package/source/schema/Meadow-Endpoint-New.js +0 -37
  106. package/source/schema/Meadow-Endpoint-Schema.js +0 -37
  107. package/source/schema/Meadow-Endpoint-Validate.js +0 -43
  108. package/test/Animal.json +0 -140
  109. package/test/MeadowEndpoints_disabledAuth_tests.js +0 -1325
  110. package/test/MeadowEndpoints_trustedSession_tests.js +0 -1731
  111. package/test/load/artillery-low.yml +0 -10
  112. package/test/load/cloud9setup.sh +0 -25
  113. package/test/load/package.json +0 -19
  114. package/test/load/test-schema-initializedatabase.sql +0 -29
  115. package/test/load/test-schema.json +0 -119
  116. package/test/load/test-server.js +0 -157
  117. package/test/scripts/InitializeDatabase-C9.sql +0 -7
  118. /package/{test/schemas → test_support/model}/json_schema/BookStore-Extended.json +0 -0
  119. /package/{test/schemas → test_support/model}/json_schema/BookStore-PICT.json +0 -0
  120. /package/{test/schemas → test_support/model}/json_schema/BookStore.json +0 -0
  121. /package/{test/schemas → test_support/model}/json_schema/README.md +0 -0
  122. /package/{test/schemas → test_support/model}/meadow_schema/BookStore-MeadowSchema-Author.json +0 -0
  123. /package/{test/schemas → test_support/model}/meadow_schema/BookStore-MeadowSchema-Book.json +0 -0
  124. /package/{test/schemas → test_support/model}/meadow_schema/BookStore-MeadowSchema-BookAuthorJoin.json +0 -0
  125. /package/{test/schemas → test_support/model}/meadow_schema/BookStore-MeadowSchema-BookPrice.json +0 -0
  126. /package/{test/schemas → test_support/model}/meadow_schema/BookStore-MeadowSchema-Review.json +0 -0
  127. /package/{test/schemas → test_support/model}/meadow_schema/README.md +0 -0
@@ -0,0 +1,225 @@
1
+ /**
2
+ * Meadow Endpoint Utility Class - Parse a Filter String and put it into a Query.
3
+ *
4
+ * @license MIT
5
+ *
6
+ * @author Steven Velozo <steven@velozo.com>
7
+ * @module Meadow
8
+ */
9
+ /**
10
+ * Parse GET-passed Filter Strings, turn the results into proper Meadow query stanzas
11
+
12
+ Take the filter and return an array of filter instructions
13
+ Basic instruction anatomy:
14
+ INSTRUCTION~FIELD~OPERATOR~VALUE
15
+ FOP - Filter Open Paren
16
+ FOP~0~(~0
17
+ FCP - Filter Close Paren
18
+ FCP~0~)~0
19
+ FBV - Filter By Value (left-side AND connected)
20
+ FBV~Category~EQ~Books
21
+ Possible comparisons:
22
+ * EQ - Equals To (=)
23
+ * NE - Not Equals To (!=)
24
+ * GT - Greater Than (>)
25
+ * GE - Greater Than or Equals To (>=)
26
+ * LT - Less Than (<)
27
+ * LE - Less Than or Equals To (<=)
28
+ * LK - Like (Like)
29
+ * IN - Is NULL
30
+ * NN - Is NOT NULL
31
+ * INN - IN list
32
+ FBVOR - Filter By Value (left-side OR connected)
33
+ FBL - Filter By List (value list, separated by commas)
34
+ FBL~Category~EQ~Books,Movies
35
+ FBD - Filter by Date (exclude time)
36
+ FBD~UpdateDate~EQ~2015-10-01
37
+ FSF - Filter Sort Field
38
+ FSF~Category~ASC~0
39
+ FSF~Category~DESC~0
40
+ FDST - Filter by Distinct (adds distinct keyword to Read and Count queries)
41
+ FDST~0~0~0~
42
+
43
+ This means: FBV~Category~EQ~Books~FBV~PublishedYear~GT~2000~FSF~PublishedYear~DESC~0
44
+ Filters down to ALL BOOKS PUBLUSHED AFTER 2000 IN DESCENDING ORDER
45
+ */
46
+
47
+ class MeadowEndpointsFilterParser
48
+ {
49
+ constructor(pController)
50
+ {
51
+ this._Controller = pController;
52
+ }
53
+
54
+ // Get the comparison operator for use in a query stanza
55
+ getFilterComparisonOperator(pFilterOperator)
56
+ {
57
+ let tmpOperator = '=';
58
+ switch(pFilterOperator)
59
+ {
60
+ case 'EQ':
61
+ tmpOperator = '=';
62
+ break;
63
+ case 'NE':
64
+ tmpOperator = '!=';
65
+ break;
66
+ case 'GT':
67
+ tmpOperator = '>';
68
+ break;
69
+ case 'GE':
70
+ tmpOperator = '>=';
71
+ break;
72
+ case 'LT':
73
+ tmpOperator = '<';
74
+ break;
75
+ case 'LE':
76
+ tmpOperator = '<=';
77
+ break;
78
+ case 'LK':
79
+ tmpOperator = 'LIKE';
80
+ break;
81
+ case 'NLK':
82
+ tmpOperator = 'NOT LIKE';
83
+ break;
84
+ case 'IN':
85
+ tmpOperator = 'IS NULL';
86
+ break;
87
+ case 'NN':
88
+ tmpOperator = 'IS NOT NULL';
89
+ break;
90
+ case 'INN':
91
+ tmpOperator = 'IN';
92
+ break;
93
+ case 'FOP':
94
+ tmpOperator = '(';
95
+ break;
96
+ case 'FCP':
97
+ tmpOperator = ')';
98
+ break;
99
+ }
100
+ return tmpOperator;
101
+ }
102
+
103
+ addFilterStanzaToQuery(pFilterStanza, pQuery)
104
+ {
105
+ if (!pFilterStanza.Instruction)
106
+ {
107
+ return false;
108
+ }
109
+
110
+ switch(pFilterStanza.Instruction)
111
+ {
112
+ case 'FBV': // Filter by Value (left-side AND)
113
+ pQuery.addFilter(pFilterStanza.Field, pFilterStanza.Value, this.getFilterComparisonOperator(pFilterStanza.Operator), 'AND');
114
+ break;
115
+
116
+ case 'FBVOR': // Filter by Value (left-side OR)
117
+ pQuery.addFilter(pFilterStanza.Field, pFilterStanza.Value, this.getFilterComparisonOperator(pFilterStanza.Operator), 'OR');
118
+ break;
119
+
120
+ case 'FBL': // Filter by List (left-side AND)
121
+ // Just split the value by comma for now. May want to revisit better characters or techniques later.
122
+ pQuery.addFilter(pFilterStanza.Field, pFilterStanza.Value.split(','), this.getFilterComparisonOperator(pFilterStanza.Operator), 'AND');
123
+ break;
124
+
125
+ case 'FBLOR': // Filter by List (left-side OR)
126
+ // Just split the value by comma for now. May want to revisit better characters or techniques later.
127
+ pQuery.addFilter(pFilterStanza.Field, pFilterStanza.Value.split(','), this.getFilterComparisonOperator(pFilterStanza.Operator), 'OR');
128
+ break;
129
+
130
+ case 'FBD': // Filter by Date (exclude time)
131
+ pQuery.addFilter(`DATE(${pFilterStanza.Field})`, pFilterStanza.Value.split(','), this.getFilterComparisonOperator(pFilterStanza.Operator), 'AND', pFilterStanza.Field);
132
+ break;
133
+
134
+ case 'FBDOR': // Filter by Date (exclude time)
135
+ pQuery.addFilter(`DATE(${pFilterStanza.Field})`, pFilterStanza.Value.split(','), this.getFilterComparisonOperator(pFilterStanza.Operator), 'OR', pFilterStanza.Field);
136
+ break;
137
+
138
+ case 'FSF': // Filter Sort Field
139
+ const tmpSortDirection = (pFilterStanza.Operator === 'DESC') ? 'Descending' : 'Ascending';
140
+ pQuery.addSort({ Column: pFilterStanza.Field, Direction: tmpSortDirection });
141
+ break;
142
+
143
+ case 'FOP': // Filter Open Paren
144
+ pQuery.addFilter('', '', '(');
145
+ break;
146
+
147
+ case 'FCP': // Filter Close Paren
148
+ pQuery.addFilter('', '', ')');
149
+ break;
150
+
151
+ case 'FDST': // Filter Distinct
152
+ // ensure we don't break if using an older foxhound version
153
+ if (pQuery.setDistinct)
154
+ {
155
+ pQuery.setDistinct(true);
156
+ }
157
+ break;
158
+
159
+ default:
160
+ //console.log('Unparsable filter stanza.');
161
+ return false;
162
+ break;
163
+ }
164
+
165
+ // Be paranoid about the instruction
166
+ pFilterStanza.Instruction = false;
167
+ return true;
168
+ };
169
+
170
+ parseFilter(pFilterString, pQuery)
171
+ {
172
+ if (typeof(pFilterString) !== 'string')
173
+ {
174
+ return false;
175
+ }
176
+
177
+ const tmpFilterTerms = pFilterString.split('~');
178
+
179
+ if (tmpFilterTerms.length < 4)
180
+ {
181
+ return true;
182
+ }
183
+
184
+ let tmpFilterStanza = { Instruction: false };
185
+
186
+ for (let i = 0; i < tmpFilterTerms.length; i++)
187
+ {
188
+ switch(i % 4)
189
+ {
190
+ case 0: // INSTRUCTION
191
+ this.addFilterStanzaToQuery(tmpFilterStanza, pQuery);
192
+ //console.log(i+' Instruction: '+tmpFilterTerms[i]);
193
+ tmpFilterStanza = (
194
+ {
195
+ Instruction: tmpFilterTerms[i],
196
+ Field: '',
197
+ Operator: '',
198
+ Value: ''
199
+ });
200
+ break;
201
+
202
+ case 1: // FIELD
203
+ //console.log(i+' Field: '+tmpFilterTerms[i]);
204
+ tmpFilterStanza.Field = tmpFilterTerms[i];
205
+ break;
206
+
207
+ case 2: // OPERATOR
208
+ //console.log(i+' Operator: '+tmpFilterTerms[i]);
209
+ tmpFilterStanza.Operator = tmpFilterTerms[i];
210
+ break;
211
+
212
+ case 3: // VALUE
213
+ //console.log(i+' Value: '+tmpFilterTerms[i]);
214
+ tmpFilterStanza.Value = tmpFilterTerms[i];
215
+ break;
216
+ }
217
+ }
218
+
219
+ this.addFilterStanzaToQuery(tmpFilterStanza, pQuery);
220
+
221
+ return true;
222
+ };
223
+ }
224
+
225
+ module.exports = MeadowEndpointsFilterParser;
@@ -0,0 +1,48 @@
1
+ class MeadowEndpointsSessionMarshaler
2
+ {
3
+ constructor(pController)
4
+ {
5
+ this._Controller = pController;
6
+ }
7
+
8
+ getSessionData(pRequest)
9
+ {
10
+ let tmpSession = Object.assign({}, this._Controller.settings.MeadowEndpointsDefaultSessionObject);
11
+
12
+ switch (this._Controller.settings.MeadowEndpointsSessionDataSource || 'Request')
13
+ {
14
+ default:
15
+ this._LogController.warn(`Unknown session source configured: ${_SessionDataSource} - defaulting to Request for backward compatibility`);
16
+ case 'Request':
17
+ // noop - already set by orator-session
18
+ tmpSession = this._Controller.extend(tmpSession, pRequest.UserSession);
19
+ break;
20
+ case 'None':
21
+ break;
22
+ case 'Header':
23
+ try
24
+ {
25
+ const tmpHeaderSessionString = pRequest.headers['x-trusted-session'];
26
+ if (!tmpHeaderSessionString)
27
+ {
28
+ break;
29
+ }
30
+ tmpHeaderSession = JSON.parse(tmpHeaderSessionString);
31
+ tmpSession = this._Controller.extend(tmpSession, pRequest.tmpHeaderSession);
32
+ }
33
+ catch (pError)
34
+ {
35
+ this._LogController.error(`Meadow Endpoints attempted to process a Header Session String with value [${tmpHeaderSessionString}] and failed -- likely culprit is bad JSON.`)
36
+ }
37
+ break;
38
+ }
39
+
40
+ // Do we keep this here for backwards compatibility?
41
+ // Yes this makes sense here.
42
+ pRequest.UserSession = tmpSession;
43
+
44
+ return tmpSession;
45
+ }
46
+ }
47
+
48
+ module.exports = MeadowEndpointsSessionMarshaler;
@@ -0,0 +1,66 @@
1
+ /**
2
+ * Meadow Endpoint Streamer - Stream an array of recods as JSON to an output stream.
3
+ */
4
+ const libAsyncEachSeries = require('async/eachSeries');
5
+ const JSONStream = require('JSONStream');
6
+
7
+ class MeadowEndpointsStreamRecordArray
8
+ {
9
+ constructor(pController)
10
+ {
11
+ this._Controller = pController;
12
+ }
13
+
14
+ chunk(pInput, pChunkSize, pChunkCache)
15
+ {
16
+ let tmpInputArray = [...pInput];
17
+ // Note lodash defaults to 1, underscore defaults to 0
18
+ let tmpChunkSize = (typeof(pChunkSize) == 'number') ? pChunkSize : 0;
19
+ let tmpChunkCache = (typeof(pChunkCache) != 'undefined') ? pChunkCache : [];
20
+
21
+ if (tmpChunkSize <= 0)
22
+ {
23
+ return tmpChunkCache;
24
+ }
25
+
26
+ while (tmpInputArray.length)
27
+ {
28
+ tmpChunkCache.push(tmpInputArray.splice(0, tmpChunkSize));
29
+ }
30
+
31
+ return tmpChunkCache;
32
+ }
33
+
34
+ streamRecordArray(pResponse, pRecords, fCallback)
35
+ {
36
+ // for meadow invoke, writeHead isn't provided, so just call send(), which is the shim it uses...
37
+ // also, for small arrays, don't bother with the async serialization; this threshold could use tuning
38
+ if (!pResponse.writeHead || !Array.isArray(pRecords) || pRecords.length < 2500)
39
+ {
40
+ pResponse.send(pRecords);
41
+ return fCallback();
42
+ }
43
+
44
+ pResponse.writeHead(200,
45
+ {
46
+ 'content-type': 'application/json',
47
+ });
48
+
49
+ const recordJsonMarshaller = JSONStream.stringify();
50
+ recordJsonMarshaller.pipe(pResponse);
51
+
52
+ // we write the records in chunks; doing one per loop is very inefficient, doing all is the same as not doing this at all
53
+ libAsyncEachSeries(this.chunk(pRecords, 1000), (pRecordChunk, fNext) =>
54
+ {
55
+ pRecordChunk.forEach(recordJsonMarshaller.write);
56
+ setImmediate(fNext);
57
+ },
58
+ (error) =>
59
+ {
60
+ recordJsonMarshaller.end();
61
+ fCallback(error);
62
+ });
63
+ }
64
+ }
65
+
66
+ module.exports = MeadowEndpointsStreamRecordArray;
@@ -0,0 +1,49 @@
1
+ /**
2
+ * Meadow Endpoint - Count a Record
3
+ */
4
+ const doAPIEndpointCount = function(pRequest, pResponse, fNext)
5
+ {
6
+ let tmpRequestState = this.initializeRequestState(pRequest, 'Count');
7
+ let fBehaviorInjector = (pBehaviorHash) => { return (fStageComplete) => { this.BehaviorInjection.runBehavior(pBehaviorHash, this, pRequest, tmpRequestState, fStageComplete); }; };
8
+
9
+ this.waterfall(
10
+ [
11
+ (fStageComplete) =>
12
+ {
13
+ tmpRequestState.Query = this.DAL.query;
14
+ if (typeof(pRequest.params.Filter) === 'string')
15
+ {
16
+ // If a filter has been passed in, parse it and add the values to the query.
17
+ this.parseFilter(pRequest.params.Filter, tmpRequestState.Query);
18
+ }
19
+ else if (pRequest.params.Filter)
20
+ {
21
+ tmpRequestState.Query.setFilter(pRequest.params.Filter);
22
+ }
23
+ return fStageComplete();
24
+ },
25
+ fBehaviorInjector(`Count-QueryConfiguration`),
26
+ (fStageComplete) =>
27
+ {
28
+ this.DAL.doCount(tmpRequestState.Query,
29
+ (pError, pQuery, pCount) =>
30
+ {
31
+ tmpRequestState.Result = {Count:pCount};
32
+ return fStageComplete(pError);
33
+ });
34
+ },
35
+ (fStageComplete) =>
36
+ {
37
+ pResponse.send(tmpRequestState.Result);
38
+ this.log.requestCompletedSuccessfully(pRequest, tmpRequestState, `Delivered recordset count of ${tmpRequestState.Result.Count} for ${this.DAL.scope}.`);
39
+ return fStageComplete();
40
+ }
41
+ ],
42
+ (pError) =>
43
+ {
44
+ return this.ErrorHandler.handleErrorIfSet(pRequest, tmpRequestState, pResponse, pError, fNext);
45
+ }
46
+ );
47
+ };
48
+
49
+ module.exports = doAPIEndpointCount;
@@ -0,0 +1,40 @@
1
+ /**
2
+ * Meadow Endpoint - Count a Record filtered by a single value
3
+ */
4
+ const doAPIEndpointCountBy = function(pRequest, pResponse, fNext)
5
+ {
6
+ let tmpRequestState = this.initializeRequestState(pRequest, 'CountBy');
7
+ let fBehaviorInjector = (pBehaviorHash) => { return (fStageComplete) => { this.BehaviorInjection.runBehavior(pBehaviorHash, this, pRequest, tmpRequestState, fStageComplete); }; };
8
+
9
+ this.waterfall(
10
+ [
11
+ (fStageComplete) =>
12
+ {
13
+ tmpRequestState.Query = this.DAL.query;
14
+ tmpRequestState.Query.addFilter(pRequest.params.ByField, pRequest.params.ByValue, '=', 'AND', 'RequestByField');
15
+ return fStageComplete();
16
+ },
17
+ fBehaviorInjector(`CountBy-QueryConfiguration`),
18
+ (fStageComplete) =>
19
+ {
20
+ this.DAL.doCount(tmpRequestState.Query,
21
+ (pError, pQuery, pCount) =>
22
+ {
23
+ tmpRequestState.Result = {Count:pCount};
24
+ return fStageComplete(pError);
25
+ });
26
+ },
27
+ (fStageComplete) =>
28
+ {
29
+ this.log.requestCompletedSuccessfully(pRequest, tmpRequestState, 'Delivered recordset count of '+tmpRequestState.Result.Count+'.');
30
+ pResponse.send(tmpRequestState.Result);
31
+ return fStageComplete();
32
+ }
33
+ ],
34
+ (pError) =>
35
+ {
36
+ return this.ErrorHandler.handleErrorIfSet(pRequest, tmpRequestState, pResponse, pError, fNext);
37
+ });
38
+ };
39
+
40
+ module.exports = doAPIEndpointCountBy;
@@ -0,0 +1,53 @@
1
+ /**
2
+ * Meadow Endpoint - Create a set of Record in Bulk
3
+ */
4
+
5
+ const doCreate = require('./Meadow-Operation-Create.js');
6
+
7
+ const doAPIEndpointBulkCreate = function(pRequest, pResponse, fNext)
8
+ {
9
+ let tmpRequestState = this.initializeRequestState(pRequest, 'CreateBulk');
10
+ let fBehaviorInjector = (pBehaviorHash) => { return (fStageComplete) => { this.BehaviorInjection.runBehavior(pBehaviorHash, this, pRequest, tmpRequestState, fStageComplete); }; };
11
+
12
+ tmpRequestState.CreatedRecords = [];
13
+
14
+ this.waterfall(
15
+ [
16
+ (fStageComplete) =>
17
+ {
18
+ if (!Array.isArray(pRequest.body))
19
+ {
20
+ return fStageComplete(this.ErrorHandler.getError('Bulk record create failure - a valid array of records to create is required.', 500));
21
+ }
22
+ pRequest.RecordsToBulkCreate = pRequest.body;
23
+
24
+ return fStageComplete();
25
+ },
26
+ fBehaviorInjector(`CreateBulk-PreOperation`),
27
+ (fStageComplete) =>
28
+ {
29
+ // TODO: Research parallelism opportunities from custom routes
30
+ this.eachLimit(pRequest.RecordsToBulkCreate, 1,
31
+ (pRecord, fCallback) =>
32
+ {
33
+ doCreate.call(this, pRecord, pRequest, tmpRequestState, pResponse, fCallback);
34
+ }, fStageComplete);
35
+ },
36
+ fBehaviorInjector(`CreateBulk-PostOperation`),
37
+ (fStageComplete) =>
38
+ {
39
+ return this.doStreamRecordArray(pResponse, tmpRequestState.CreatedRecords, fStageComplete);
40
+ },
41
+ (fStageComplete) =>
42
+ {
43
+ this.log.requestCompletedSuccessfully(pRequest, tmpRequestState, `Bulk created ${tmpRequestState.CreatedRecords.length} records`);
44
+ return fStageComplete();
45
+ }
46
+ ],
47
+ (pError) =>
48
+ {
49
+ return this.ErrorHandler.handleErrorIfSet(pRequest, tmpRequestState, pResponse, pError, fNext);
50
+ });
51
+ };
52
+
53
+ module.exports = doAPIEndpointBulkCreate;
@@ -0,0 +1,58 @@
1
+ /**
2
+ * Meadow Endpoint - Create a Record
3
+ */
4
+ const doCreate = require('./Meadow-Operation-Create.js');
5
+
6
+ const doAPIEndpointCreate = function(pRequest, pResponse, fNext)
7
+ {
8
+ let tmpRequestState = this.initializeRequestState(pRequest, 'Create');
9
+ let fBehaviorInjector = (pBehaviorHash) => { return (fStageComplete) => { this.BehaviorInjection.runBehavior(pBehaviorHash, this, pRequest, tmpRequestState, fStageComplete); }; };
10
+
11
+ this.waterfall(
12
+ [
13
+ (fStageComplete) =>
14
+ {
15
+ if (typeof(pRequest.body) !== 'object')
16
+ {
17
+ return fStageComplete(this.ErrorHandler.getError('Record create failure - a valid record is required.', 500));
18
+ }
19
+
20
+ return fStageComplete();
21
+ },
22
+ (fStageComplete) =>
23
+ {
24
+ doCreate.call(this, pRequest.body, pRequest, tmpRequestState, pResponse, fStageComplete);
25
+ },
26
+ (fStageComplete) =>
27
+ {
28
+ if (tmpRequestState.RecordCreateError)
29
+ {
30
+ return fStageComplete(tmpRequestState.RecordCreateErrorObject);
31
+ }
32
+ if (tmpRequestState.CreatedRecords.length < 1)
33
+ {
34
+ return fStageComplete(this.ErrorHandler.getError('Unknown record create failure - no created records returned.', 500));
35
+ }
36
+
37
+ tmpRequestState.Record = tmpRequestState.CreatedRecords[0];
38
+
39
+ return fStageComplete();
40
+ },
41
+ (fStageComplete) =>
42
+ {
43
+ pResponse.send(tmpRequestState.Record);
44
+ return fStageComplete();
45
+ },
46
+ (fStageComplete) =>
47
+ {
48
+ this.log.requestCompletedSuccessfully(pRequest, tmpRequestState, `Created a ${this.DAL.scope} record ID ${tmpRequestState.Record[this.DAL.defaultIdentifier]}`);
49
+ return fStageComplete();
50
+ }
51
+ ],
52
+ (pError) =>
53
+ {
54
+ return this.ErrorHandler.handleErrorIfSet(pRequest, tmpRequestState, pResponse, pError, fNext);
55
+ });
56
+ };
57
+
58
+ module.exports = doAPIEndpointCreate;
@@ -0,0 +1,83 @@
1
+ /**
2
+ * Meadow Operation - Create a record function
3
+ */
4
+ const doCreate = function(pRecord, pRequest, pRequestState, pResponse, fCallback)
5
+ {
6
+ // This is a virtual operation
7
+ let tmpRequestState = this.cloneAsyncSafeRequestState(pRequestState, 'doCreate');
8
+ let fBehaviorInjector = (pBehaviorHash) => { return (fStageComplete) => { this.BehaviorInjection.runBehavior(pBehaviorHash, this, pRequest, tmpRequestState, fStageComplete); }; };
9
+
10
+ if (!Array.isArray(tmpRequestState.ParentRequestState.CreatedRecords))
11
+ {
12
+ tmpRequestState.ParentRequestState.CreatedRecords = [];
13
+ }
14
+
15
+ this.waterfall(
16
+ [
17
+ (fStageComplete) =>
18
+ {
19
+ tmpRequestState.RecordToCreate = pRecord;
20
+
21
+ //Make sure record gets created with a customerID
22
+ if (!tmpRequestState.RecordToCreate.hasOwnProperty('IDCustomer') && this.DAL.jsonSchema.properties.hasOwnProperty('IDCustomer'))
23
+ {
24
+ tmpRequestState.RecordToCreate.IDCustomer = tmpRequestState.SessionData.CustomerID || 0;
25
+ }
26
+
27
+ return fStageComplete();
28
+ },
29
+ (fStageComplete) => { this.BehaviorInjection.runBehavior(`Create-PreOperation`, this, pRequest, tmpRequestState, fStageComplete); },
30
+ (fStageComplete) =>
31
+ {
32
+ // Prepare create query
33
+ tmpRequestState.Query = this.DAL.query;
34
+ tmpRequestState.Query.setIDUser(tmpRequestState.SessionData.UserID);
35
+ tmpRequestState.Query.addRecord(tmpRequestState.RecordToCreate);
36
+ return fStageComplete();
37
+ },
38
+ (fStageComplete) => { this.BehaviorInjection.runBehavior(`Create-QueryConfiguration`, this, pRequest, tmpRequestState, fStageComplete); },
39
+ (fStageComplete) =>
40
+ {
41
+ // Do the actual create operation with the DAL
42
+ this.DAL.doCreate(tmpRequestState.Query,
43
+ (pError, pQuery, pReadQuery, pNewRecord) =>
44
+ {
45
+ if (pError)
46
+ {
47
+ return fStageComplete(pError);
48
+ }
49
+ if (!pNewRecord)
50
+ {
51
+ return fStageComplete(this.ErrorHandler.getError(`Error in DAL Create: No record returned from persistence engine.`, 500));
52
+ }
53
+
54
+ tmpRequestState.Record = pNewRecord;
55
+
56
+ return fStageComplete();
57
+ });
58
+ },
59
+ (fStageComplete) => { return this.BehaviorInjection.runBehavior(`Create-PostOperation`, this, pRequest, tmpRequestState, fStageComplete); },
60
+ (fStageComplete) =>
61
+ {
62
+ tmpRequestState.ParentRequestState.CreatedRecords.push(tmpRequestState.Record);
63
+ this.log.requestCompletedSuccessfully(pRequest, tmpRequestState, `Created a record with ${this.DAL.defaultIdentifier} = ${tmpRequestState.Record[this.DAL.defaultIdentifier]}`);
64
+ return fStageComplete();
65
+ }
66
+ ],
67
+ (pError) =>
68
+ {
69
+ if (pError)
70
+ {
71
+ tmpRequestState.RecordToCreate.Error = pError;
72
+
73
+ tmpRequestState.ParentRequestState.RecordCreateError = true;
74
+ tmpRequestState.ParentRequestState.RecordCreateErrorObject = pError;
75
+
76
+ tmpRequestState.ParentRequestState.CreatedRecords.push(tmpRequestState.RecordToCreate);
77
+ }
78
+
79
+ return fCallback();
80
+ });
81
+ };
82
+
83
+ module.exports = doCreate;