fable 3.0.36 → 3.0.38

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 (58) hide show
  1. package/.browserslistrc +1 -1
  2. package/.config/configstore/update-notifier-npm.json +1 -1
  3. package/.config/vscode-sqltools/runningInfo.json +1 -1
  4. package/Dockerfile_LUXURYCode +6 -8
  5. package/debug/Harness.js +3 -4
  6. package/dist/fable.js +38 -8
  7. package/dist/fable.min.js +55 -3
  8. package/dist/fable.min.js.map +1 -1
  9. package/gulpfile-config.json +2 -2
  10. package/package.json +3 -2
  11. package/retold-harness/bookstore-api-endpoint-exercises.paw +0 -0
  12. package/retold-harness/bookstore-serve-meadow-endpoint-apis-run.js +6 -0
  13. package/{.config/retold-harness → retold-harness}/bookstore-serve-meadow-endpoint-apis.js +1 -0
  14. package/{.config/retold-harness → retold-harness}/package.json +5 -3
  15. package/source/Fable.js +8 -17
  16. package/source/services/Fable-Service-CSVParser.js +199 -0
  17. package/source/services/Fable-Service-DataFormat.js +0 -3
  18. package/source/services/Fable-Service-RestClient.js +130 -26
  19. package/test/CSVParser_tests.js +66 -0
  20. package/test/RestClient_test.js +69 -3
  21. package/test/data/books.csv +10001 -0
  22. package/.config/retold-harness/bookstore-api-endpoint-exercises.paw +0 -0
  23. /package/{.config/retold-harness → retold-harness}/Bookstore-Import-Books.sh +0 -0
  24. /package/{.config/retold-harness → retold-harness}/MySQL-Laden-Entry.sh +0 -0
  25. /package/{.config/retold-harness → retold-harness}/MySQL-Security.sql +0 -0
  26. /package/{.config/retold-harness → retold-harness}/bookstore-configuration.json +0 -0
  27. /package/{.config/retold-harness → retold-harness}/bookstore-import-books-run.js +0 -0
  28. /package/{.config/retold-harness → retold-harness}/bookstore-import-books.js +0 -0
  29. /package/{.config/retold-harness → retold-harness}/bookstore-serve-meadow-endpoint-apis-IPC.js +0 -0
  30. /package/{.config/retold-harness → retold-harness}/data/books.csv +0 -0
  31. /package/{.config/retold-harness → retold-harness}/model/ddl/BookStore.ddl +0 -0
  32. /package/{.config/retold-harness → retold-harness}/model/generated_diagram/README.md +0 -0
  33. /package/{.config/retold-harness → retold-harness}/model/generated_diagram/Stricture_Output.dot +0 -0
  34. /package/{.config/retold-harness → retold-harness}/model/generated_diagram/Stricture_Output.png +0 -0
  35. /package/{.config/retold-harness → retold-harness}/model/generated_documentation/Dictionary.md +0 -0
  36. /package/{.config/retold-harness → retold-harness}/model/generated_documentation/Model-Author.md +0 -0
  37. /package/{.config/retold-harness → retold-harness}/model/generated_documentation/Model-Book.md +0 -0
  38. /package/{.config/retold-harness → retold-harness}/model/generated_documentation/Model-BookAuthorJoin.md +0 -0
  39. /package/{.config/retold-harness → retold-harness}/model/generated_documentation/Model-BookPrice.md +0 -0
  40. /package/{.config/retold-harness → retold-harness}/model/generated_documentation/Model-Review.md +0 -0
  41. /package/{.config/retold-harness → retold-harness}/model/generated_documentation/ModelChangeTracking.md +0 -0
  42. /package/{.config/retold-harness → retold-harness}/model/generated_documentation/README.md +0 -0
  43. /package/{.config/retold-harness → retold-harness}/model/json_schema/BookStore-Extended.json +0 -0
  44. /package/{.config/retold-harness → retold-harness}/model/json_schema/BookStore-PICT.json +0 -0
  45. /package/{.config/retold-harness → retold-harness}/model/json_schema/BookStore.json +0 -0
  46. /package/{.config/retold-harness → retold-harness}/model/json_schema/README.md +0 -0
  47. /package/{.config/retold-harness → retold-harness}/model/manual_scripts/DropTables.sql +0 -0
  48. /package/{.config/retold-harness → retold-harness}/model/manual_scripts/README.md +0 -0
  49. /package/{.config/retold-harness → retold-harness}/model/meadow_schema/BookStore-MeadowSchema-Author.json +0 -0
  50. /package/{.config/retold-harness → retold-harness}/model/meadow_schema/BookStore-MeadowSchema-Book.json +0 -0
  51. /package/{.config/retold-harness → retold-harness}/model/meadow_schema/BookStore-MeadowSchema-BookAuthorJoin.json +0 -0
  52. /package/{.config/retold-harness → retold-harness}/model/meadow_schema/BookStore-MeadowSchema-BookPrice.json +0 -0
  53. /package/{.config/retold-harness → retold-harness}/model/meadow_schema/BookStore-MeadowSchema-Review.json +0 -0
  54. /package/{.config/retold-harness → retold-harness}/model/meadow_schema/README.md +0 -0
  55. /package/{.config/retold-harness → retold-harness}/model/sql_create/BookStore-CreateDatabase.mysql.sql +0 -0
  56. /package/{.config/retold-harness → retold-harness}/model/sql_create/README.md +0 -0
  57. /package/{.config/retold-harness → retold-harness}/test_old/Tests.js +0 -0
  58. /package/{.config/retold-harness → retold-harness}/test_old/untitled.js +0 -0
@@ -5,7 +5,7 @@
5
5
 
6
6
  "LibraryOutputFolder": "./dist/",
7
7
 
8
- "LibraryUniminifiedFileName": "fable.compatible.js",
8
+ "LibraryUniminifiedFileName": "fable.js",
9
9
 
10
- "LibraryMinifiedFileName": "fable.compatible.min.js"
10
+ "LibraryMinifiedFileName": "fable.min.js"
11
11
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fable",
3
- "version": "3.0.36",
3
+ "version": "3.0.38",
4
4
  "description": "An entity behavior management and API bundling library.",
5
5
  "main": "source/Fable.js",
6
6
  "scripts": {
@@ -10,7 +10,8 @@
10
10
  "build": "./node_modules/.bin/gulp build",
11
11
  "build-compatible": "GULP_CUSTOM_BUILD_TARGET=compatible ./node_modules/.bin/gulp build",
12
12
  "docker-dev-build-image": "docker build ./ -f Dockerfile_LUXURYCode -t retold/fable:local",
13
- "docker-dev-run": "docker run -it -d --name retold-fable-dev -p 30001:8080 -v \"$PWD/.config:/home/coder/.config\" -v \"$PWD:/home/coder/fable\" -u \"$(id -u):$(id -g)\" -e \"DOCKER_USER=$USER\" retold/fable:local"
13
+ "docker-dev-run": "docker run -it -d --name retold-fable-dev -p 30001:8080 -p 8086:8086 -v \"$PWD/.config:/home/coder/.config\" -v \"$PWD:/home/coder/fable\" -u \"$(id -u):$(id -g)\" -e \"DOCKER_USER=$USER\" retold/fable:local",
14
+ "docker-dev-shell": "docker exec -it retold-fable-dev /bin/bash"
14
15
  },
15
16
  "mocha": {
16
17
  "diff": true,
@@ -0,0 +1,6 @@
1
+ const libServer = require('./bookstore-serve-meadow-endpoint-apis.js');
2
+ let _Orator = libServer(
3
+ ()=>
4
+ {
5
+ console.log('API service is started!');
6
+ });
@@ -3,6 +3,7 @@
3
3
  */
4
4
 
5
5
  /**
6
+ * @license MIT
6
7
  * @author <steven@velozo.com>
7
8
  */
8
9
 
@@ -4,17 +4,19 @@
4
4
  "description": "Harness data import and server.",
5
5
  "main": "bookstore-serve-meadow-endpoints-apis.js",
6
6
  "scripts": {
7
+ "start": "node bookstore-serve-meadow-endpoint-apis-run.js",
7
8
  "test": "echo \"Error: no test specified\" && exit 1"
8
9
  },
9
10
  "author": "",
10
11
  "license": "MIT",
11
12
  "dependencies": {
12
13
  "async": "^3.2.4",
13
- "fable": "^3.0.35",
14
+ "fable": "^3.0.37",
14
15
  "meadow": "^2.0.4",
15
- "meadow-endpoints": "^3.0.7",
16
- "mysql2": "^3.3.0",
16
+ "meadow-endpoints": "^4.0.2",
17
+ "mysql2": "^3.3.1",
17
18
  "orator": "^3.0.11",
19
+ "orator-serviceserver-restify": "^1.0.4",
18
20
  "papaparse": "^5.4.1"
19
21
  }
20
22
  }
package/source/Fable.js CHANGED
@@ -9,15 +9,6 @@ const libFableLog = require('fable-log');
9
9
 
10
10
  const libFableServiceManager = require('./Fable-ServiceManager.js');
11
11
 
12
- // Default Services
13
- const libFableServiceEnvironmentData = require('./services/Fable-Service-EnvironmentData.js');
14
- const libFableServiceDataFormat = require('./services/Fable-Service-DataFormat.js');
15
- const libFableServiceMetaTemplate = require('./services/Fable-Service-MetaTemplate.js');
16
- const libFableServiceOperation = require('./services/Fable-Service-Operation.js');
17
- const libFableServiceRestClient = require('./services/Fable-Service-RestClient.js');
18
- const libFableServiceTemplate = require('./services/Fable-Service-Template.js');
19
- const libFableServiceUtility = require('./services/Fable-Service-Utility.js');
20
-
21
12
  class Fable
22
13
  {
23
14
  constructor(pSettings)
@@ -51,14 +42,14 @@ class Fable
51
42
  this.serviceManager.connectPreinitServiceProviderInstance(this._coreServices.SettingsManager);
52
43
 
53
44
  // Initialize and instantiate the default baked-in Data Arithmatic service
54
- this.serviceManager.addAndInstantiateServiceType('EnvironmentData', libFableServiceEnvironmentData);
55
- this.serviceManager.addServiceType('Template', libFableServiceTemplate);
56
- this.serviceManager.addServiceType('MetaTemplate', libFableServiceMetaTemplate);
57
- this.serviceManager.addAndInstantiateServiceType('DataFormat', libFableServiceDataFormat);
58
- this.serviceManager.addAndInstantiateServiceType('Utility', libFableServiceUtility);
59
- this.serviceManager.addServiceType('Operation', libFableServiceOperation);
60
- this.serviceManager.addServiceType('RestClient', libFableServiceRestClient);
61
-
45
+ this.serviceManager.addAndInstantiateServiceType('EnvironmentData', require('./services/Fable-Service-EnvironmentData.js'));
46
+ this.serviceManager.addServiceType('Template', require('./services/Fable-Service-Template.js'));
47
+ this.serviceManager.addServiceType('MetaTemplate', require('./services/Fable-Service-MetaTemplate.js'));
48
+ this.serviceManager.addAndInstantiateServiceType('DataFormat', require('./services/Fable-Service-DataFormat.js'));
49
+ this.serviceManager.addAndInstantiateServiceType('Utility', require('./services/Fable-Service-Utility.js'));
50
+ this.serviceManager.addServiceType('Operation', require('./services/Fable-Service-Operation.js'));
51
+ this.serviceManager.addServiceType('RestClient', require('./services/Fable-Service-RestClient.js'));
52
+ this.serviceManager.addServiceType('CSVParser', require('./services/Fable-Service-CSVParser.js'));
62
53
  }
63
54
 
64
55
  get settings()
@@ -0,0 +1,199 @@
1
+ const libFableServiceProviderBase = require('fable-serviceproviderbase');
2
+ /**
3
+ * Parsing CSVs. Why? Because it's a thing that needs to be done.
4
+ *
5
+ * 1. And the other node CSV parsers had issues with the really messy files we had.
6
+ *
7
+ *
8
+ * 2. None of the CSV parsers dealt with and multi-line quoted string columns
9
+ * which are apparently a-ok according to the official spec.
10
+ * Plus a lot of them are asynchronous because apparently that's the best way to
11
+ * do anything; unfortunately some files have a sequence issue with that.
12
+ *
13
+ * @class CSVParser
14
+ */
15
+ class CSVParser extends libFableServiceProviderBase
16
+ {
17
+ constructor(pFable, pOptions, pServiceHash)
18
+ {
19
+ super(pFable, pOptions, pServiceHash);
20
+
21
+ this.serviceType = 'CSVParser';
22
+
23
+ this.Header = [];
24
+ this.HeaderFieldNames = [];
25
+
26
+ this.Delimiter = ',';
27
+ this.QuoteCharacter = '"';
28
+
29
+ this.CleanCharacters = ['\r'];
30
+
31
+ this.HeaderLineIndex = 0;
32
+ this.HasHeader = true;
33
+ this.HasSetHeader = false;
34
+ this.EmitHeader = false;
35
+
36
+ this.EmitJSON = true;
37
+
38
+ this.EscapedQuoteString = '&quot;';
39
+
40
+ // Current Line Parsing State
41
+ this.CurrentLine = '';
42
+ this.CurrentRecord = [];
43
+
44
+ this.InQuote = false;
45
+ this.InEscapedQuote = false;
46
+
47
+ this.LinesParsed = 0;
48
+ this.RowsEmitted = 0;
49
+ }
50
+
51
+ marshalRowToJSON(pRowArray)
52
+ {
53
+ if (!Array.isArray(pRowArray))
54
+ {
55
+ return false;
56
+ }
57
+
58
+ for (let i = this.HeaderFieldNames.length; i < pRowArray.length; i++)
59
+ {
60
+ this.HeaderFieldNames[i] = `${i}`;
61
+ }
62
+
63
+ let tmpObject = {};
64
+
65
+ for (let i = 0; i < pRowArray.length; i++)
66
+ {
67
+ tmpObject[this.HeaderFieldNames[i]] = pRowArray[i];
68
+ }
69
+
70
+ return tmpObject;
71
+ }
72
+
73
+ // Set the header data, for use in marshalling to JSON.
74
+ setHeader (pHeaderArray)
75
+ {
76
+ this.Header = pHeaderArray;
77
+
78
+ for (let i = 0; i < this.Header.length; i++)
79
+ {
80
+ if (typeof(this.Header[i]) == 'undefined')
81
+ {
82
+ this.HeaderFieldNames[i] = `${i}`;
83
+ }
84
+ else
85
+ {
86
+ this.HeaderFieldNames[i] = this.Header[i].toString();
87
+ }
88
+ }
89
+ }
90
+
91
+ resetRowState()
92
+ {
93
+ this.CurrentRecord = [];
94
+ }
95
+
96
+ pushLine()
97
+ {
98
+ for (let i = 0; i < this.CleanCharacters.length; i++)
99
+ {
100
+ this.CurrentLine = this.CurrentLine.replace(this.CleanCharacters[i],'');
101
+ }
102
+ this.CurrentRecord.push(this.CurrentLine);
103
+ this.CurrentLine = '';
104
+ }
105
+
106
+ emitRow(pFormatAsJSON)
107
+ {
108
+ let tmpFormatAsJSON = (typeof(pFormatAsJSON) == 'undefined') ? this.EmitJSON : pFormatAsJSON;
109
+
110
+ this.RowsEmitted++;
111
+ let tmpCompletedRecord = this.CurrentRecord;
112
+ this.CurrentRecord = [];
113
+
114
+ if (tmpFormatAsJSON)
115
+ {
116
+ return this.marshalRowToJSON(tmpCompletedRecord);
117
+ }
118
+ else
119
+ {
120
+ return tmpCompletedRecord;
121
+ }
122
+ }
123
+
124
+ parseCSVLine (pLineString)
125
+ {
126
+ this.LinesParsed++;
127
+
128
+ for (let i = 0; i < pLineString.length; i++)
129
+ {
130
+ if ((!this.InQuote) && (pLineString[i] == this.Delimiter))
131
+ {
132
+ this.pushLine();
133
+ }
134
+ else if (pLineString[i] == this.QuoteCharacter)
135
+ {
136
+ // If we are in the second part of an escaped quote, ignore it.
137
+ if (this.InEscapedQuote)
138
+ {
139
+ this.InEscapedQuote = false;
140
+ }
141
+ // If we aren't in a quote, enter quote
142
+ else if (!this.InQuote)
143
+ {
144
+ this.InQuote = true;
145
+ }
146
+ // We are in a quote, so peek forward to see if this is an "escaped" quote pair
147
+ else if ((i < pLineString.length) && (pLineString[i+1] == this.QuoteCharacter))
148
+ {
149
+ this.CurrentLine += this.EscapedQuoteString;
150
+ this.InEscapedQuote = true;
151
+ }
152
+ // We are in a quote, this isn't an "escaped" quote pair, so go out of quote mode
153
+ else
154
+ {
155
+ this.InQuote = false;
156
+ }
157
+ }
158
+ else
159
+ {
160
+ this.CurrentLine += pLineString[i];
161
+ }
162
+ }
163
+
164
+ // See if we are in a multiline quoted entry -- if not, emit the row.
165
+ if (!this.InQuote)
166
+ {
167
+ // Push the last remaining column from the buffer to the current line.
168
+ this.pushLine();
169
+
170
+ // Check to see if there is a header -- and if so, if this is the header row
171
+ if (this.HasHeader && !this.HasSetHeader && (this.RowsEmitted == this.HeaderLineIndex))
172
+ {
173
+ this.HasSetHeader = true;
174
+ // Override the format as json bit
175
+ this.setHeader(this.emitRow(false));
176
+
177
+ // No matter what, formatting this as JSON is silly and we don't want to go there anyway.
178
+ if (this.EmitHeader)
179
+ {
180
+ return this.Header;
181
+ }
182
+ else
183
+ {
184
+ return false;
185
+ }
186
+ }
187
+ else
188
+ {
189
+ return this.emitRow();
190
+ }
191
+ }
192
+ else
193
+ {
194
+ return false;
195
+ }
196
+ };
197
+ }
198
+
199
+ module.exports = CSVParser;
@@ -1,6 +1,3 @@
1
- /**
2
- */
3
-
4
1
  const libFableServiceProviderBase = require('fable-serviceproviderbase');
5
2
  /**
6
3
  * Data Formatting and Translation Functions
@@ -19,64 +19,88 @@ class FableServiceRestClient extends libFableServiceBase
19
19
  this.serviceType = 'RestClient';
20
20
  }
21
21
 
22
- getJSON(pOptionsOrURL, fCallback)
22
+ executeChunkedRequest(pOptions, fCallback)
23
23
  {
24
- return this.getRaw(pOptionsOrURL,
25
- (pError, pResponse, pResult) =>
24
+ pOptions.RequestStartTime = this.fable.log.getTimeStamp();
25
+
26
+ if (this.TraceLog)
27
+ {
28
+ this.fable.log.debug(`Beginning ${pOptions.method} request to ${pOptions.url} at ${pOptions.RequestStartTime}`);
29
+ }
30
+
31
+ return libSimpleGet(pOptions,
32
+ (pError, pResponse)=>
26
33
  {
27
34
  if (pError)
28
35
  {
29
- return fCallback(pError, pResponse, pResult);
36
+ return fCallback(pError, pResponse);
30
37
  }
31
38
 
32
- if (pResponse.statusCode != 200)
39
+ if (this.TraceLog)
33
40
  {
34
- return fCallback(new Error(`Invalid status code ${pResponse.statusCode}`), pResponse, pResult);
41
+ let tmpConnectTime = this.fable.log.getTimeStamp();
42
+ this.fable.log.debug(`--> ${pOptions.method} connected in ${this.dataFormat.formatTimeDelta(pOptions.RequestStartTime, tmpConnectTime)}ms code ${pResponse.statusCode}`);
35
43
  }
36
44
 
37
- return fCallback(pError, pResponse, JSON.parse(pResult));
45
+ let tmpData = '';
46
+
47
+ pResponse.on('data', (pChunk) =>
48
+ {
49
+ // For JSON, the chunk is the serialized object.
50
+ if (this.TraceLog)
51
+ {
52
+ let tmpChunkTime = this.fable.log.getTimeStamp();
53
+ this.fable.log.debug(`--> ${pOptions.method} data chunk size ${pChunk.length}b received in ${this.dataFormat.formatTimeDelta(pOptions.RequestStartTime, tmpChunkTime)}ms`);
54
+ }
55
+ tmpData += pChunk;
56
+ });
57
+
58
+ pResponse.on('end', ()=>
59
+ {
60
+ if (this.TraceLog)
61
+ {
62
+ let tmpCompletionTime = this.fable.log.getTimeStamp();
63
+ this.fable.log.debug(`==> ${pOptions.method} completed data size ${tmpData.length}b received in ${this.dataFormat.formatTimeDelta(pOptions.RequestStartTime, tmpCompletionTime)}ms`);
64
+ }
65
+ return fCallback(pError, pResponse, tmpData);
66
+ });
38
67
  });
39
68
  }
40
69
 
41
- getRaw(pOptionsOrURL, fCallback)
70
+ executeJSONRequest(pOptions, fCallback)
42
71
  {
43
- let tmpRequestOptions = (typeof(pOptions) == 'object') ? pOptions : {};
44
- if (typeof(pOptionsOrURL) == 'string')
45
- {
46
- tmpRequestOptions.url = pOptionsOrURL;
47
- }
72
+ pOptions.json = true;
73
+
74
+ pOptions.RequestStartTime = this.fable.log.getTimeStamp();
48
75
 
49
- let tmpRequestStartTime = this.fable.log.getTimeStamp();
50
76
  if (this.TraceLog)
51
77
  {
52
- let tmpConnectTime = this.fable.log.getTimeStamp();
53
- this.fable.log.debug(`Beginning GET request to ${tmpRequestOptions.url} at ${tmpRequestStartTime}`);
78
+ this.fable.log.debug(`Beginning ${pOptions.method} JSON request to ${pOptions.url} at ${pOptions.RequestStartTime}`);
54
79
  }
55
80
 
56
- libSimpleGet.get(tmpRequestOptions,
81
+ return libSimpleGet(pOptions,
57
82
  (pError, pResponse)=>
58
83
  {
59
84
  if (pError)
60
85
  {
61
- return fCallback(pError, pResponse, tmpRequestOptions);
86
+ return fCallback(pError, pResponse);
62
87
  }
63
88
 
64
89
  if (this.TraceLog)
65
90
  {
66
91
  let tmpConnectTime = this.fable.log.getTimeStamp();
67
- this.fable.log.debug(`--> GET connected in ${this.dataFormat.formatTimeDelta(tmpRequestStartTime, tmpConnectTime)}ms code ${pResponse.statusCode}`);
92
+ this.fable.log.debug(`--> JSON ${pOptions.method} connected in ${this.dataFormat.formatTimeDelta(pOptions.RequestStartTime, tmpConnectTime)}ms code ${pResponse.statusCode}`);
68
93
  }
69
94
 
70
- let tmpData = '';
71
-
72
- pResponse.on('data', (pChunk)=>
95
+ pResponse.on('data', (pChunk) =>
73
96
  {
74
97
  if (this.TraceLog)
75
98
  {
76
99
  let tmpChunkTime = this.fable.log.getTimeStamp();
77
- this.fable.log.debug(`--> GET data chunk size ${pChunk.length}b received in ${this.dataFormat.formatTimeDelta(tmpRequestStartTime, tmpChunkTime)}ms`);
100
+ this.fable.log.debug(`--> JSON ${pOptions.method} data chunk size ${pChunk.length}b received in ${this.dataFormat.formatTimeDelta(pOptions.RequestStartTime, tmpChunkTime)}ms`);
78
101
  }
79
- tmpData += pChunk;
102
+ // In a JSON request, the chunk is the serialized method.
103
+ return fCallback(pError, pResponse, JSON.parse(pChunk));
80
104
  });
81
105
 
82
106
  pResponse.on('end', ()=>
@@ -84,12 +108,92 @@ class FableServiceRestClient extends libFableServiceBase
84
108
  if (this.TraceLog)
85
109
  {
86
110
  let tmpCompletionTime = this.fable.log.getTimeStamp();
87
- this.fable.log.debug(`==> GET completed data size ${tmpData.length}b received in ${this.dataFormat.formatTimeDelta(tmpRequestStartTime, tmpCompletionTime)}ms`);
111
+ this.fable.log.debug(`==> JSON ${pOptions.method} completed - received in ${this.dataFormat.formatTimeDelta(pOptions.RequestStartTime, tmpCompletionTime)}ms`);
88
112
  }
89
- return fCallback(pError, pResponse, tmpData);
90
113
  });
91
114
  });
92
115
  }
116
+
117
+ getJSON(pOptionsOrURL, fCallback)
118
+ {
119
+ let tmpRequestOptions = (typeof(pOptions) == 'object') ? pOptions : {};
120
+ if (typeof(pOptionsOrURL) == 'string')
121
+ {
122
+ tmpRequestOptions.url = pOptionsOrURL;
123
+ }
124
+
125
+ tmpRequestOptions.method = 'GET';
126
+
127
+ return this.executeJSONRequest(tmpRequestOptions, fCallback);
128
+ }
129
+
130
+ putJSON(pOptions, fCallback)
131
+ {
132
+ if (typeof(pOptions.body) != 'object')
133
+ {
134
+ return fCallback(new Error(`PUT JSON Error Invalid options object`));
135
+ }
136
+
137
+ pOptions.method = 'PUT';
138
+
139
+ return this.executeJSONRequest(pOptions, fCallback);
140
+ }
141
+
142
+ postJSON(pOptions, fCallback)
143
+ {
144
+ if (typeof(pOptions.body) != 'object')
145
+ {
146
+ return fCallback(new Error(`POST JSON Error Invalid options object`));
147
+ }
148
+
149
+ pOptions.method = 'POST';
150
+
151
+ return this.executeJSONRequest(pOptions, fCallback);
152
+ }
153
+
154
+ patchJSON(pOptions, fCallback)
155
+ {
156
+ if (typeof(pOptions.body) != 'object')
157
+ {
158
+ return fCallback(new Error(`PATCH JSON Error Invalid options object`));
159
+ }
160
+
161
+ pOptions.method = 'PATCH';
162
+
163
+ return this.executeJSONRequest(pOptions, fCallback);
164
+ }
165
+
166
+ headJSON(pOptions, fCallback)
167
+ {
168
+ if (typeof(pOptions.body) != 'object')
169
+ {
170
+ return fCallback(new Error(`HEAD JSON Error Invalid options object`));
171
+ }
172
+
173
+ pOptions.method = 'HEAD';
174
+
175
+ return this.executeJSONRequest(pOptions, fCallback);
176
+ }
177
+
178
+ delJSON(pOptions, fCallback)
179
+ {
180
+ pOptions.method = 'DELETE';
181
+
182
+ return this.executeJSONRequest(pOptions, fCallback);
183
+ }
184
+
185
+ getRawText(pOptionsOrURL, fCallback)
186
+ {
187
+ let tmpRequestOptions = (typeof(pOptions) == 'object') ? pOptions : {};
188
+ if (typeof(pOptionsOrURL) == 'string')
189
+ {
190
+ tmpRequestOptions.url = pOptionsOrURL;
191
+ }
192
+
193
+ tmpRequestOptions.method = 'GET';
194
+
195
+ return this.executeChunkedRequest(tmpRequestOptions, fCallback);
196
+ }
93
197
  }
94
198
 
95
199
  module.exports = FableServiceRestClient;
@@ -0,0 +1,66 @@
1
+ /**
2
+ * Unit tests for Fable
3
+ *
4
+ * @license MIT
5
+ *
6
+ * @author Steven Velozo <steven@velozo.com>
7
+ */
8
+
9
+ var libFable = require('../source/Fable.js');
10
+
11
+ const libFS = require('fs');
12
+ const libReadline = require('readline');
13
+
14
+ var Chai = require("chai");
15
+ var Expect = Chai.expect;
16
+
17
+ suite
18
+ (
19
+ 'CSV Parser',
20
+ function()
21
+ {
22
+ suite
23
+ (
24
+ 'Parse CSV',
25
+ function()
26
+ {
27
+ test
28
+ (
29
+ 'Pull CSV Data',
30
+ function(fDone)
31
+ {
32
+ let testFable = new libFable();
33
+ let tmpCSVParser = testFable.serviceManager.instantiateServiceProvider('CSVParser', {Name: 'Big Complex Integration Operation'}, 'CSV Parser-123');
34
+ let tmpRecords = [];
35
+
36
+ const tmpReadline = libReadline.createInterface(
37
+ {
38
+ input: libFS.createReadStream(`${__dirname}/data/books.csv`),
39
+ crlfDelay: Infinity
40
+ });
41
+
42
+ tmpReadline.on('line',
43
+ (pLine) =>
44
+ {
45
+ let tmpRecord = tmpCSVParser.parseCSVLine(pLine);
46
+ if (tmpRecord)
47
+ {
48
+ tmpRecords.push(tmpRecord);
49
+ }
50
+ });
51
+
52
+ tmpReadline.on('close',
53
+ () =>
54
+ {
55
+ console.log(`Readline closed... testing import!`);
56
+ Expect(tmpRecords.length).to.equal(10000);
57
+ Expect(tmpRecords[0].authors).to.equal('Suzanne Collins');
58
+ return fDone();
59
+ });
60
+
61
+ }
62
+ );
63
+ }
64
+ );
65
+ }
66
+ );
@@ -38,16 +38,82 @@ suite
38
38
  let tmpRestClient = testFable.serviceManager.instantiateServiceProvider('RestClient', {TraceLog: true}, 'RestClient-99');
39
39
 
40
40
  // Download the wiktionary entry for dog!
41
- tmpRestClient.getJSON('https://en.wiktionary.org/w/api.php?action=parse&prop=wikitext&format=json&page=dog',
41
+ tmpRestClient.getJSON('http://localhost:8086/1.0/Author/1',
42
42
  (pError, pResponse, pBody)=>
43
43
  {
44
44
  Expect(pBody).to.be.an('object');
45
- Expect(pBody.hasOwnProperty('parse')).to.equal(true);
46
- Expect(pBody.parse.title).to.equal('dog');
45
+ Expect(pBody.hasOwnProperty('Name')).to.equal(true);
46
+ Expect(pBody.Name).to.equal('Suzanne Collins');
47
47
  fTestComplete();
48
48
  });
49
49
  }
50
50
  );
51
+ test
52
+ (
53
+ 'Perform a POST request.',
54
+ function(fTestComplete)
55
+ {
56
+ let testFable = new libFable();
57
+ // Instantiate the RestClient Service Provider
58
+ let tmpRestClient = testFable.serviceManager.instantiateServiceProvider('RestClient', {TraceLog: true}, 'RestClient-99');
59
+
60
+ // Download the wiktionary entry for dog!
61
+ tmpRestClient.postJSON({url: 'http://localhost:8086/1.0/Author', body:{Name:'Test Author'}},
62
+ (pError, pResponse, pBody)=>
63
+ {
64
+ Expect(pBody).to.be.an('object');
65
+ Expect(pBody.hasOwnProperty('Name')).to.equal(true);
66
+ Expect(pBody.Name).to.equal('Test Author');
67
+ fTestComplete();
68
+ });
69
+ }
70
+ );
71
+ test
72
+ (
73
+ 'Perform a PUT request.',
74
+ function(fTestComplete)
75
+ {
76
+ let testFable = new libFable();
77
+ // Instantiate the RestClient Service Provider
78
+ let tmpRestClient = testFable.serviceManager.instantiateServiceProvider('RestClient', {TraceLog: true}, 'RestClient-99');
79
+
80
+ // Download the wiktionary entry for dog!
81
+ tmpRestClient.putJSON({url: 'http://localhost:8086/1.0/Author/Upsert', body:{GUIDAuthor:'TestAuthor', Name:'Test Author 2'}},
82
+ (pError, pResponse, pBody)=>
83
+ {
84
+ Expect(pBody).to.be.an('object');
85
+ Expect(pBody.hasOwnProperty('Name')).to.equal(true);
86
+ Expect(pBody.Name).to.equal('Test Author 2');
87
+ fTestComplete();
88
+ });
89
+ }
90
+ );
91
+ test
92
+ (
93
+ 'Perform an UPSERT request then a DELETE.',
94
+ function(fTestComplete)
95
+ {
96
+ let testFable = new libFable();
97
+ // Instantiate the RestClient Service Provider
98
+ let tmpRestClient = testFable.serviceManager.instantiateServiceProvider('RestClient', {TraceLog: true}, 'RestClient-99');
99
+
100
+ // Download the wiktionary entry for dog!
101
+ tmpRestClient.putJSON({url: 'http://localhost:8086/1.0/Author/Upsert', body:{Name:'Test Author 2 DELETE'}},
102
+ (pError, pResponse, pBody)=>
103
+ {
104
+ Expect(pBody).to.be.an('object');
105
+ Expect(pBody.hasOwnProperty('Name')).to.equal(true);
106
+ Expect(pBody.Name).to.equal('Test Author 2 DELETE');
107
+ tmpRestClient.delJSON({url: `http://localhost:8086/1.0/Author/${pBody.IDAuthor}`},
108
+ (pDeleteError, pDeleteResponse, pDeleteBody) =>
109
+ {
110
+ Expect(pDeleteBody.Count)
111
+ .to.equal(1);
112
+ fTestComplete();
113
+ });
114
+ });
115
+ }
116
+ );
51
117
  }
52
118
  );
53
119
  }