meadow-endpoints 2.0.12 → 2.0.13

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.
package/package.json CHANGED
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "meadow-endpoints",
3
- "version": "2.0.12",
3
+ "version": "2.0.13",
4
4
  "description": "Automatic API endpoints for Meadow data.",
5
5
  "main": "source/Meadow-Endpoints.js",
6
6
  "scripts": {
7
7
  "start": "node source/Meadow-Endpoints.js",
8
8
  "coverage": "nyc npm run test && nyc report --reporter=lcov",
9
- "test": "./node_modules/mocha/bin/_mocha --exit -u tdd -R spec"
9
+ "test": "./node_modules/.bin/mocha --exit -u tdd -R spec"
10
10
  },
11
11
  "repository": {
12
12
  "type": "git",
@@ -34,7 +34,8 @@
34
34
  "dependencies": {
35
35
  "async": "2.6.1",
36
36
  "JSONStream": "^1.3.5",
37
- "meadow": "~1.0.30",
37
+ "meadow": "~1.0.31",
38
+ "meadow-filter": "^1.0.1",
38
39
  "mysql2": "1.6.1",
39
40
  "orator": "~2.0.2",
40
41
  "underscore": "1.9.1"
@@ -56,6 +56,7 @@ var MeadowEndpoints = function()
56
56
 
57
57
  ReadSelectList: require('./crud/Meadow-Endpoint-ReadSelectList.js'),
58
58
  ReadLiteList: require('./crud/Meadow-Endpoint-ReadLiteList.js'),
59
+ ReadDistinctList: require('./crud/Meadow-Endpoint-ReadDistinctList.js'),
59
60
 
60
61
  Update: require('./crud/Meadow-Endpoint-Update.js'),
61
62
  Updates: require('./crud/Meadow-Endpoint-BulkUpdate.js'),
@@ -172,6 +173,10 @@ var MeadowEndpoints = function()
172
173
  // GET [/1.0/SomeEndpoint/LiteExtended/:ExtraColumns/:Begin/:Cap]
173
174
  // GET [/1.0/SomeEndpoint/LiteExtended/:ExtraColumns/FilteredTo/:Filter]
174
175
  // GET [/1.0/SomeEndpoint/LiteExtended/:ExtraColumns/FilteredTo/:Filter/:Begin/:Cap]
176
+ // GET [/1.0/SomeEndpoint/Distinct/:Columns]
177
+ // GET [/1.0/SomeEndpoint/Distinct/:Columns/:Begin/:Cap]
178
+ // GET [/1.0/SomeEndpoint/Distinct/:Columns/FilteredTo/:Filter]
179
+ // GET [/1.0/SomeEndpoint/Distinct/:Columns/FilteredTo/:Filter/:Begin/:Cap]
175
180
 
176
181
  Update: true,
177
182
  // PUT [/1.0/SomeEndpoint]
@@ -290,11 +295,13 @@ var MeadowEndpoints = function()
290
295
  var connectRoutes = function(pRestServer)
291
296
  {
292
297
  // TODO: Pull version from the config file.
293
- var tmpEndpointVersion = '1.0';
298
+ const tmpEndpointVersion = _Fable.settings.MeadowEndpointVersion || '1.0';
294
299
  // TODO: Allow the user to override the endpoint "name" eventually.
295
- var tmpEndpointName = _Meadow.scope;
300
+ const tmpEndpointName = _Meadow.scope;
296
301
 
297
- _Fable.log.trace('Creating endpoint', {Version:tmpEndpointVersion, Name:tmpEndpointName});
302
+ _Fable.log.trace('Creating endpoint', { Version: tmpEndpointVersion, Name: tmpEndpointName });
303
+
304
+ const tmpEndpointPrefix = `/${tmpEndpointVersion}/${tmpEndpointName}`;
298
305
 
299
306
  if (!_AttachedRequestHandlers)
300
307
  {
@@ -310,15 +317,15 @@ var MeadowEndpoints = function()
310
317
  // technically block out the routes for the IDRecord 'Schema' (e.g. /1.0/EntityName/Schema)
311
318
  if (_EnabledBehaviors.Schema)
312
319
  {
313
- pRestServer.get('/1.0/'+tmpEndpointName+'/Schema', _EndpointAuthenticators.Schema, wireState, _Endpoints.Schema);
320
+ pRestServer.get(`${tmpEndpointPrefix}/Schema`, _EndpointAuthenticators.Schema, wireState, _Endpoints.Schema);
314
321
  }
315
322
  if (_EnabledBehaviors.New)
316
323
  {
317
- pRestServer.get('/1.0/'+tmpEndpointName+'/Schema/New', _EndpointAuthenticators.New, wireState, _Endpoints.New);
324
+ pRestServer.get(`${tmpEndpointPrefix}/Schema/New`, _EndpointAuthenticators.New, wireState, _Endpoints.New);
318
325
  }
319
326
  if (_EnabledBehaviors.Validate)
320
327
  {
321
- pRestServer.post('/1.0/'+tmpEndpointName+'/Schema/Validate', _CommonServices.bodyParser(), _EndpointAuthenticators.Validate, wireState, _Endpoints.Validate);
328
+ pRestServer.post(`${tmpEndpointPrefix}/Schema/Validate`, _CommonServices.bodyParser(), _EndpointAuthenticators.Validate, wireState, _Endpoints.Validate);
322
329
  }
323
330
 
324
331
  // Custom single record endpoints
@@ -326,52 +333,56 @@ var MeadowEndpoints = function()
326
333
  // Standard CRUD and Count endpoints
327
334
  if (_EnabledBehaviors.Create)
328
335
  {
329
- pRestServer.post('/1.0/'+tmpEndpointName, _CommonServices.bodyParser(), _EndpointAuthenticators.Create, wireState, _Endpoints.Create);
330
- pRestServer.post('/1.0/'+tmpEndpointName+'s', _CommonServices.bodyParser(), _EndpointAuthenticators.Create, wireState, _Endpoints.Creates);
336
+ pRestServer.post(`${tmpEndpointPrefix}`, _CommonServices.bodyParser(), _EndpointAuthenticators.Create, wireState, _Endpoints.Create);
337
+ pRestServer.post(`${tmpEndpointPrefix}s`, _CommonServices.bodyParser(), _EndpointAuthenticators.Create, wireState, _Endpoints.Creates);
331
338
  }
332
339
  if (_EnabledBehaviors.Read)
333
340
  {
334
- pRestServer.get('/1.0/'+tmpEndpointName+'/Max/:ColumnName', _EndpointAuthenticators.Read, wireState, _Endpoints.ReadMax);
335
- pRestServer.get('/1.0/'+tmpEndpointName+'/:IDRecord', _EndpointAuthenticators.Read, wireState, _Endpoints.Read);
341
+ pRestServer.get(`${tmpEndpointPrefix}/Max/:ColumnName`, _EndpointAuthenticators.Read, wireState, _Endpoints.ReadMax);
342
+ pRestServer.get(`${tmpEndpointPrefix}/:IDRecord`, _EndpointAuthenticators.Read, wireState, _Endpoints.Read);
336
343
  }
337
344
  if (_EnabledBehaviors.Reads)
338
345
  {
339
- pRestServer.get('/1.0/'+tmpEndpointName+'s', _EndpointAuthenticators.Reads, wireState, _Endpoints.Reads);
340
- pRestServer.get('/1.0/'+tmpEndpointName+'s/By/:ByField/:ByValue', _EndpointAuthenticators.Reads, wireState, _Endpoints.ReadsBy);
341
- pRestServer.get('/1.0/'+tmpEndpointName+'s/By/:ByField/:ByValue/:Begin/:Cap', _EndpointAuthenticators.Reads, wireState, _Endpoints.ReadsBy);
342
- pRestServer.get('/1.0/'+tmpEndpointName+'s/FilteredTo/:Filter', _EndpointAuthenticators.Reads, wireState, _Endpoints.Reads);
343
- pRestServer.get('/1.0/'+tmpEndpointName+'s/FilteredTo/:Filter/:Begin/:Cap', _EndpointAuthenticators.Reads, wireState, _Endpoints.Reads);
344
- pRestServer.get('/1.0/'+tmpEndpointName+'Select', _EndpointAuthenticators.Reads, wireState, _Endpoints.ReadSelectList);
345
- pRestServer.get('/1.0/'+tmpEndpointName+'Select/FilteredTo/:Filter', _EndpointAuthenticators.Reads, wireState, _Endpoints.ReadSelectList);
346
- pRestServer.get('/1.0/'+tmpEndpointName+'Select/FilteredTo/:Filter/:Begin/:Cap', _EndpointAuthenticators.Reads, wireState, _Endpoints.ReadSelectList);
347
- pRestServer.get('/1.0/'+tmpEndpointName+'Select/:Begin/:Cap', _EndpointAuthenticators.Reads, wireState, _Endpoints.ReadSelectList);
348
- pRestServer.get('/1.0/'+tmpEndpointName+'s/Lite', _EndpointAuthenticators.Reads, wireState, _Endpoints.ReadLiteList);
349
- pRestServer.get('/1.0/'+tmpEndpointName+'s/Lite/FilteredTo/:Filter', _EndpointAuthenticators.Reads, wireState, _Endpoints.ReadLiteList);
350
- pRestServer.get('/1.0/'+tmpEndpointName+'s/Lite/FilteredTo/:Filter/:Begin/:Cap', _EndpointAuthenticators.Reads, wireState, _Endpoints.ReadLiteList);
351
- pRestServer.get('/1.0/'+tmpEndpointName+'s/Lite/:Begin/:Cap', _EndpointAuthenticators.Reads, wireState, _Endpoints.ReadLiteList);
352
- pRestServer.get('/1.0/'+tmpEndpointName+'s/LiteExtended/:ExtraColumns', _EndpointAuthenticators.Reads, wireState, _Endpoints.ReadLiteList);
353
- pRestServer.get('/1.0/'+tmpEndpointName+'s/LiteExtended/:ExtraColumns/FilteredTo/:Filter', _EndpointAuthenticators.Reads, wireState, _Endpoints.ReadLiteList);
354
- pRestServer.get('/1.0/'+tmpEndpointName+'s/LiteExtended/:ExtraColumns/FilteredTo/:Filter/:Begin/:Cap', _EndpointAuthenticators.Reads, wireState, _Endpoints.ReadLiteList);
355
- pRestServer.get('/1.0/'+tmpEndpointName+'s/LiteExtended/:ExtraColumns/:Begin/:Cap', _EndpointAuthenticators.Reads, wireState, _Endpoints.ReadLiteList);
356
- pRestServer.get('/1.0/'+tmpEndpointName+'s/:Begin/:Cap', _EndpointAuthenticators.Reads, wireState, _Endpoints.Reads);
346
+ pRestServer.get(`${tmpEndpointPrefix}s`, _EndpointAuthenticators.Reads, wireState, _Endpoints.Reads);
347
+ pRestServer.get(`${tmpEndpointPrefix}s/By/:ByField/:ByValue`, _EndpointAuthenticators.Reads, wireState, _Endpoints.ReadsBy);
348
+ pRestServer.get(`${tmpEndpointPrefix}s/By/:ByField/:ByValue/:Begin/:Cap`, _EndpointAuthenticators.Reads, wireState, _Endpoints.ReadsBy);
349
+ pRestServer.get(`${tmpEndpointPrefix}s/FilteredTo/:Filter`, _EndpointAuthenticators.Reads, wireState, _Endpoints.Reads);
350
+ pRestServer.get(`${tmpEndpointPrefix}s/FilteredTo/:Filter/:Begin/:Cap`, _EndpointAuthenticators.Reads, wireState, _Endpoints.Reads);
351
+ pRestServer.get(`${tmpEndpointPrefix}Select`, _EndpointAuthenticators.Reads, wireState, _Endpoints.ReadSelectList);
352
+ pRestServer.get(`${tmpEndpointPrefix}Select/FilteredTo/:Filter`, _EndpointAuthenticators.Reads, wireState, _Endpoints.ReadSelectList);
353
+ pRestServer.get(`${tmpEndpointPrefix}Select/FilteredTo/:Filter/:Begin/:Cap`, _EndpointAuthenticators.Reads, wireState, _Endpoints.ReadSelectList);
354
+ pRestServer.get(`${tmpEndpointPrefix}Select/:Begin/:Cap`, _EndpointAuthenticators.Reads, wireState, _Endpoints.ReadSelectList);
355
+ pRestServer.get(`${tmpEndpointPrefix}s/Lite`, _EndpointAuthenticators.Reads, wireState, _Endpoints.ReadLiteList);
356
+ pRestServer.get(`${tmpEndpointPrefix}s/Lite/FilteredTo/:Filter`, _EndpointAuthenticators.Reads, wireState, _Endpoints.ReadLiteList);
357
+ pRestServer.get(`${tmpEndpointPrefix}s/Lite/FilteredTo/:Filter/:Begin/:Cap`, _EndpointAuthenticators.Reads, wireState, _Endpoints.ReadLiteList);
358
+ pRestServer.get(`${tmpEndpointPrefix}s/Lite/:Begin/:Cap`, _EndpointAuthenticators.Reads, wireState, _Endpoints.ReadLiteList);
359
+ pRestServer.get(`${tmpEndpointPrefix}s/LiteExtended/:ExtraColumns`, _EndpointAuthenticators.Reads, wireState, _Endpoints.ReadLiteList);
360
+ pRestServer.get(`${tmpEndpointPrefix}s/LiteExtended/:ExtraColumns/FilteredTo/:Filter`, _EndpointAuthenticators.Reads, wireState, _Endpoints.ReadLiteList);
361
+ pRestServer.get(`${tmpEndpointPrefix}s/LiteExtended/:ExtraColumns/FilteredTo/:Filter/:Begin/:Cap`, _EndpointAuthenticators.Reads, wireState, _Endpoints.ReadLiteList);
362
+ pRestServer.get(`${tmpEndpointPrefix}s/LiteExtended/:ExtraColumns/:Begin/:Cap`, _EndpointAuthenticators.Reads, wireState, _Endpoints.ReadLiteList);
363
+ pRestServer.get(`${tmpEndpointPrefix}s/Distinct/:Columns`, _EndpointAuthenticators.Reads, wireState, _Endpoints.ReadDistinctList);
364
+ pRestServer.get(`${tmpEndpointPrefix}s/Distinct/:Columns/FilteredTo/:Filter`, _EndpointAuthenticators.Reads, wireState, _Endpoints.ReadDistinctList);
365
+ pRestServer.get(`${tmpEndpointPrefix}s/Distinct/:Columns/FilteredTo/:Filter/:Begin/:Cap`, _EndpointAuthenticators.Reads, wireState, _Endpoints.ReadDistinctList);
366
+ pRestServer.get(`${tmpEndpointPrefix}s/Distinct/:Columns/:Begin/:Cap`, _EndpointAuthenticators.Reads, wireState, _Endpoints.ReadDistinctList);
367
+ pRestServer.get(`${tmpEndpointPrefix}s/:Begin/:Cap`, _EndpointAuthenticators.Reads, wireState, _Endpoints.Reads);
357
368
  }
358
369
  if (_EnabledBehaviors.Update)
359
370
  {
360
- pRestServer.put('/1.0/'+tmpEndpointName, _CommonServices.bodyParser(), _EndpointAuthenticators.Update, wireState, _Endpoints.Update);
361
- pRestServer.put('/1.0/'+tmpEndpointName+'s', _CommonServices.bodyParser(), _EndpointAuthenticators.Update, wireState, _Endpoints.Updates);
362
- pRestServer.put('/1.0/'+tmpEndpointName+'/Upsert', _CommonServices.bodyParser(), _EndpointAuthenticators.Update, wireState, _Endpoints.Upsert);
363
- pRestServer.put('/1.0/'+tmpEndpointName+'/Upserts', _CommonServices.bodyParser(), _EndpointAuthenticators.Update, wireState, _Endpoints.Upserts);
371
+ pRestServer.put(`${tmpEndpointPrefix}`, _CommonServices.bodyParser(), _EndpointAuthenticators.Update, wireState, _Endpoints.Update);
372
+ pRestServer.put(`${tmpEndpointPrefix}s`, _CommonServices.bodyParser(), _EndpointAuthenticators.Update, wireState, _Endpoints.Updates);
373
+ pRestServer.put(`${tmpEndpointPrefix}/Upsert`, _CommonServices.bodyParser(), _EndpointAuthenticators.Update, wireState, _Endpoints.Upsert);
374
+ pRestServer.put(`${tmpEndpointPrefix}/Upserts`, _CommonServices.bodyParser(), _EndpointAuthenticators.Update, wireState, _Endpoints.Upserts);
364
375
  }
365
376
  if (_EnabledBehaviors.Delete)
366
377
  {
367
- pRestServer.del('/1.0/'+tmpEndpointName, _CommonServices.bodyParser(), _EndpointAuthenticators.Delete, wireState, _Endpoints.Delete);
368
- pRestServer.del('/1.0/'+tmpEndpointName+'/:IDRecord', _EndpointAuthenticators.Delete, wireState, _Endpoints.Delete);
378
+ pRestServer.del(`${tmpEndpointPrefix}`, _CommonServices.bodyParser(), _EndpointAuthenticators.Delete, wireState, _Endpoints.Delete);
379
+ pRestServer.del(`${tmpEndpointPrefix}/:IDRecord`, _EndpointAuthenticators.Delete, wireState, _Endpoints.Delete);
369
380
  }
370
381
  if (_EnabledBehaviors.Count)
371
382
  {
372
- pRestServer.get('/1.0/'+tmpEndpointName+'s/Count', _EndpointAuthenticators.Count, wireState, _Endpoints.Count);
373
- pRestServer.get('/1.0/'+tmpEndpointName+'s/Count/By/:ByField/:ByValue', _EndpointAuthenticators.Count, wireState, _Endpoints.CountBy);
374
- pRestServer.get('/1.0/'+tmpEndpointName+'s/Count/FilteredTo/:Filter', _EndpointAuthenticators.Count, wireState, _Endpoints.Count);
383
+ pRestServer.get(`${tmpEndpointPrefix}s/Count`, _EndpointAuthenticators.Count, wireState, _Endpoints.Count);
384
+ pRestServer.get(`${tmpEndpointPrefix}s/Count/By/:ByField/:ByValue`, _EndpointAuthenticators.Count, wireState, _Endpoints.CountBy);
385
+ pRestServer.get(`${tmpEndpointPrefix}s/Count/FilteredTo/:Filter`, _EndpointAuthenticators.Count, wireState, _Endpoints.Count);
375
386
  }
376
387
  };
377
388
 
@@ -493,7 +504,7 @@ var MeadowEndpoints = function()
493
504
 
494
505
  connectRoutes: connectRoutes,
495
506
 
496
- parseFilter: require(__dirname+'/crud/Meadow-Filter-Parse.js'),
507
+ parseFilter: require('meadow-filter').parse,
497
508
 
498
509
  // Expose the DAL
499
510
  DAL: _Meadow,
@@ -8,7 +8,7 @@
8
8
  */
9
9
 
10
10
  var libAsync = require('async');
11
- var meadowFilterParser = require('./Meadow-Filter-Parse.js');
11
+ const meadowFilterParser = require('meadow-filter').parse;
12
12
  /**
13
13
  * Count a record using the Meadow DAL object
14
14
  */
@@ -0,0 +1,146 @@
1
+ /**
2
+ * Meadow Endpoint - Read a list of Records with a specified set of columns, distinct by those columns.
3
+ *
4
+ * @license MIT
5
+ *
6
+ * @author Alex Decker <alex.decker@headlight.com>
7
+ * @module Meadow
8
+ */
9
+ const libAsync = require('async');
10
+ const meadowFilterParser = require('meadow-filter').parse;
11
+ const marshalDistinctList = require('./Meadow-Marshal-DistinctList.js');
12
+ const streamRecordsToResponse = require('./Meadow-StreamRecordArray');
13
+
14
+ /**
15
+ * Get a set of records from a DAL.
16
+ */
17
+ const doAPIReadDistinctEndpoint = function(pRequest, pResponse, fNext)
18
+ {
19
+ // This state is the requirement for the UserRoleIndex value in the UserSession object... processed by default as >=
20
+ // The default here is that any authenticated user can use this endpoint.
21
+ pRequest.EndpointAuthorizationRequirement = pRequest.EndpointAuthorizationLevels.Reads;
22
+
23
+ // INJECT: Pre authorization (for instance to change the authorization level)
24
+
25
+ if (pRequest.CommonServices.authorizeEndpoint(pRequest, pResponse, fNext) === false)
26
+ {
27
+ // If this endpoint fails, it's sent an error automatically.
28
+ return;
29
+ }
30
+
31
+ let tmpDistinctColumns;
32
+ libAsync.waterfall(
33
+ [
34
+ // 1a. Get the records
35
+ function (fStageComplete)
36
+ {
37
+ pRequest.Query = pRequest.DAL.query.setDistinct(true);
38
+ // TODO: Limit the query to the columns we need for the templated expression
39
+
40
+ let tmpCap = false;
41
+ let tmpBegin = false;
42
+ if (typeof(pRequest.params.Begin) === 'string' ||
43
+ typeof(pRequest.params.Begin) === 'number')
44
+ {
45
+ tmpBegin = parseInt(pRequest.params.Begin, 10);
46
+ }
47
+ if (typeof(pRequest.params.Cap) === 'string' ||
48
+ typeof(pRequest.params.Cap) === 'number')
49
+ {
50
+ tmpCap = parseInt(pRequest.params.Cap, 10);
51
+ }
52
+ else
53
+ {
54
+ //maximum number of records to return by default on Read queries. Override via "MeadowDefaultMaxCap" fable setting.
55
+ tmpCap = pRequest.DEFAULT_MAX_CAP;
56
+ }
57
+ pRequest.Query.setCap(tmpCap).setBegin(tmpBegin);
58
+ if (typeof(pRequest.params.Filter) === 'string')
59
+ {
60
+ // If a filter has been passed in, parse it and add the values to the query.
61
+ meadowFilterParser(pRequest.params.Filter, pRequest.Query);
62
+ }
63
+ else if (pRequest.params.Filter)
64
+ {
65
+ pRequest.Query.setFilter(pRequest.params.Filter);
66
+ }
67
+ if (typeof(pRequest.params.Columns) === 'string')
68
+ {
69
+ tmpDistinctColumns = pRequest.params.Columns.split(',');
70
+ if (!tmpDistinctColumns)
71
+ {
72
+ return fStageComplete({Code:400,Message:'Columns to distinct on must be provided.'});
73
+ }
74
+ pRequest.Query.setDataElements(tmpDistinctColumns);
75
+ }
76
+ fStageComplete(false);
77
+ },
78
+ // 1b. INJECT: Query configuration
79
+ function (fStageComplete)
80
+ {
81
+ pRequest.BehaviorModifications.runBehavior('Reads-QueryConfiguration', pRequest, fStageComplete);
82
+ },
83
+ // 1b2. INJECT: Query pre-authorization behavior (ex. if authorizer needs fields to be included, it can add them)
84
+ function (fStageComplete)
85
+ {
86
+ pRequest.BehaviorModifications.runBehavior('Reads-PreAuth', pRequest, fStageComplete);
87
+ },
88
+ // 1c. Do the record read
89
+ function (fStageComplete)
90
+ {
91
+ pRequest.DAL.doReads(pRequest.Query, fStageComplete);
92
+ },
93
+ // 2. Post processing of the records
94
+ function (pQuery, pRecords, fStageComplete)
95
+ {
96
+ if (pRecords.length < 1)
97
+ {
98
+ pRecords = [];
99
+ }
100
+
101
+ pRequest.Records = pRecords;
102
+
103
+ // Complete the waterfall operation
104
+ fStageComplete(false);
105
+ },
106
+ // 2.5: Check if there is an authorizer set for this endpoint and user role combination, and authorize based on that
107
+ function (fStageComplete)
108
+ {
109
+ // shared permission with reads
110
+ pRequest.Authorizers.authorizeRequest('Reads', pRequest, fStageComplete);
111
+ },
112
+ // 2.6: Check if authorization or post processing denied security access to the record
113
+ function (fStageComplete)
114
+ {
115
+ if (pRequest.MeadowAuthorization)
116
+ {
117
+ return fStageComplete(false);
118
+ }
119
+
120
+ // It looks like this record was not authorized. Send an error.
121
+ return fStageComplete({Code:405,Message:'UNAUTHORIZED ACCESS IS NOT ALLOWED'});
122
+ },
123
+ // 3. Marshalling of records into the hash list, using underscore templates.
124
+ function (fStageComplete)
125
+ {
126
+ fStageComplete(false, marshalDistinctList(pRequest.Records, pRequest, tmpDistinctColumns));
127
+ }
128
+ ],
129
+ // 3. Return the results to the user
130
+ function(pError, pResultRecords)
131
+ {
132
+ // Remove 'Records' object from pRequest, instead return template results (pResultRecords) for the records
133
+ delete pRequest['Records'];
134
+
135
+ if (pError)
136
+ {
137
+ return pRequest.CommonServices.sendCodedError('Error retreiving a recordset.', pError, pRequest, pResponse, fNext);
138
+ }
139
+
140
+ pRequest.CommonServices.log.info('Read a recordset lite list with '+pResultRecords.length+' results.', {SessionID:pRequest.UserSession.SessionID, RequestID:pRequest.RequestUUID, RequestURL:pRequest.url, Action:pRequest.DAL.scope+'-ReadDistinct'}, pRequest);
141
+ return streamRecordsToResponse(pResponse, pResultRecords, fNext);
142
+ }
143
+ );
144
+ };
145
+
146
+ module.exports = doAPIReadDistinctEndpoint;
@@ -7,7 +7,7 @@
7
7
  * @module Meadow
8
8
  */
9
9
  var libAsync = require('async');
10
- var meadowFilterParser = require('./Meadow-Filter-Parse.js');
10
+ const meadowFilterParser = require('meadow-filter').parse;
11
11
  var marshalLiteList = require('./Meadow-Marshal-LiteList.js');
12
12
  const streamRecordsToResponse = require('./Meadow-StreamRecordArray');
13
13
 
@@ -71,6 +71,11 @@ var doAPIReadLiteEndpoint = function(pRequest, pResponse, fNext)
71
71
  {
72
72
  pRequest.BehaviorModifications.runBehavior('Reads-QueryConfiguration', pRequest, fStageComplete);
73
73
  },
74
+ // 1b2. INJECT: Query pre-authorization behavior (ex. if authorizer needs fields to be included, it can add them)
75
+ function (fStageComplete)
76
+ {
77
+ pRequest.BehaviorModifications.runBehavior('Reads-PreAuth', pRequest, fStageComplete);
78
+ },
74
79
  // 1c. Do the record read
75
80
  function (fStageComplete)
76
81
  {
@@ -92,7 +97,8 @@ var doAPIReadLiteEndpoint = function(pRequest, pResponse, fNext)
92
97
  // 2.5: Check if there is an authorizer set for this endpoint and user role combination, and authorize based on that
93
98
  function (fStageComplete)
94
99
  {
95
- pRequest.Authorizers.authorizeRequest('ReadLite', pRequest, fStageComplete);
100
+ // shared permission with reads
101
+ pRequest.Authorizers.authorizeRequest('Reads', pRequest, fStageComplete);
96
102
  },
97
103
  // 2.6: Check if authorization or post processing denied security access to the record
98
104
  function (fStageComplete)
@@ -7,7 +7,7 @@
7
7
  * @module Meadow
8
8
  */
9
9
  var libAsync = require('async');
10
- var meadowFilterParser = require('./Meadow-Filter-Parse.js');
10
+ const meadowFilterParser = require('meadow-filter').parse;
11
11
  const streamRecordsToResponse = require('./Meadow-StreamRecordArray');
12
12
 
13
13
  /**
@@ -66,6 +66,11 @@ var doAPIReadSelectListEndpoint = function(pRequest, pResponse, fNext)
66
66
  {
67
67
  pRequest.BehaviorModifications.runBehavior('Reads-QueryConfiguration', pRequest, fStageComplete);
68
68
  },
69
+ // 1b2. INJECT: Query pre-authorization behavior (ex. if authorizer needs fields to be included, it can add them)
70
+ function (fStageComplete)
71
+ {
72
+ pRequest.BehaviorModifications.runBehavior('Reads-PreAuth', pRequest, fStageComplete);
73
+ },
69
74
  // 1c. Do the record read
70
75
  function (fStageComplete)
71
76
  {
@@ -7,7 +7,7 @@
7
7
  * @module Meadow
8
8
  */
9
9
  var libAsync = require('async');
10
- var meadowFilterParser = require('./Meadow-Filter-Parse.js');
10
+ const meadowFilterParser = require('meadow-filter').parse;
11
11
  const streamRecordsToResponse = require('./Meadow-StreamRecordArray');
12
12
 
13
13
  /**
@@ -67,6 +67,11 @@ var doAPIReadsEndpoint = function(pRequest, pResponse, fNext)
67
67
  {
68
68
  pRequest.BehaviorModifications.runBehavior('Reads-QueryConfiguration', pRequest, fStageComplete);
69
69
  },
70
+ // 2b. INJECT: Query pre-authorization behavior (ex. if authorizer needs fields to be included, it can add them)
71
+ function (fStageComplete)
72
+ {
73
+ pRequest.BehaviorModifications.runBehavior('Reads-PreAuth', pRequest, fStageComplete);
74
+ },
70
75
  // 3. Execute the query
71
76
  function (fStageComplete)
72
77
  {
@@ -94,6 +94,11 @@ var doAPIReadsByEndpoint = function(pRequest, pResponse, fNext)
94
94
  {
95
95
  pRequest.BehaviorModifications.runBehavior('Reads-QueryConfiguration', pRequest, fStageComplete);
96
96
  },
97
+ // 3b. INJECT: Query pre-authorization behavior (ex. if authorizer needs fields to be included, it can add them)
98
+ function (fStageComplete)
99
+ {
100
+ pRequest.BehaviorModifications.runBehavior('Reads-PreAuth', pRequest, fStageComplete);
101
+ },
97
102
  // 4. Execute the query
98
103
  function (fStageComplete)
99
104
  {
@@ -0,0 +1,55 @@
1
+ /**
2
+ * Meadow Operation - Marshal an array of records into a lite list
3
+ *
4
+ * @license MIT
5
+ *
6
+ * @author Steven Velozo <steven@velozo.com>
7
+ * @module Meadow
8
+ */
9
+ /**
10
+ * Shared record marshaling code
11
+ */
12
+
13
+ var marshalDistinctList = (pRecords, pRequest, pFieldList) =>
14
+ {
15
+ if (pRecords.length < 1)
16
+ return [];
17
+
18
+ let tmpDistinctList = [];
19
+ // Allow the caller to pass in a list of fields.
20
+ let tmpFieldList = (typeof(pFieldList) !== 'undefined') ? pFieldList : [];
21
+
22
+ // See if this record has a GUID in the schema
23
+ let tmpGUID = (pRequest.DAL.defaultGUIdentifier && pRequest.DAL.defaultGUIdentifier.length > 0) ? pRequest.DAL.defaultGUIdentifier : false;
24
+ // Peek at the first record to check for updatedate
25
+ let tmpHasUpdateDate = (pRecords[0].hasOwnProperty('UpdateDate')) ? true : false;
26
+ //Include all GUID and ID fields on the record
27
+ let tmpRecordFields = Object.keys(pRecords[0]);
28
+
29
+ let h = 0;
30
+ while (h < tmpFieldList.length)
31
+ {
32
+ // Remove any fields in the list that aren't in the first record.
33
+ if (!pRecords[0].hasOwnProperty(tmpFieldList[0]))
34
+ tmpFieldList.splice(h, 1);
35
+ else
36
+ h++;
37
+ }
38
+
39
+ for (let i = 0; i < pRecords.length; i++)
40
+ {
41
+ let tmpDistinctRecord = { };
42
+
43
+ tmpFieldList.forEach(
44
+ (pField) =>
45
+ {
46
+ tmpDistinctRecord[pField] = pRecords[i][pField];
47
+ });
48
+
49
+ tmpDistinctList.push(tmpDistinctRecord);
50
+ }
51
+
52
+ return tmpDistinctList;
53
+ };
54
+
55
+ module.exports = marshalDistinctList;
@@ -807,7 +807,6 @@ suite
807
807
  function(fDone)
808
808
  {
809
809
  libSuperTest('http://localhost:9080/')
810
- // Get page 2, 2 records per page.
811
810
  .get('1.0/FableTests/FilteredTo/FBV~Type~EQ~Frog')
812
811
  .end(
813
812
  function (pError, pResponse)
@@ -819,13 +818,88 @@ suite
819
818
  }
820
819
  );
821
820
  }
822
- ); test
821
+ );
822
+ test
823
+ (
824
+ 'reads: get distinct values for a column',
825
+ function(fDone)
826
+ {
827
+ libSuperTest('http://localhost:9080/')
828
+ .get('1.0/FableTests/Distinct/Type')
829
+ .end(
830
+ function (pError, pResponse)
831
+ {
832
+ var tmpResults = JSON.parse(pResponse.text);
833
+ Expect(tmpResults.length).to.equal(5);
834
+ const types = tmpResults.map((r) => r.Type);
835
+ Expect(types).to.have.members(['Bunny', 'Girl', 'Dog', 'Frog', 'Mammoth']);
836
+ fDone();
837
+ }
838
+ );
839
+ }
840
+ );
841
+ test
842
+ (
843
+ 'reads: get distinct values for a column with filter',
844
+ function(fDone)
845
+ {
846
+ libSuperTest('http://localhost:9080/')
847
+ .get('1.0/FableTests/Distinct/Type/FilteredTo/FBV~IDAnimal~LT~3')
848
+ .end(
849
+ function (pError, pResponse)
850
+ {
851
+ var tmpResults = JSON.parse(pResponse.text);
852
+ Expect(tmpResults.length).to.equal(2);
853
+ const types = new Set(tmpResults.map((r) => r.Type));
854
+ Expect(types.size).to.equal(2);
855
+ fDone();
856
+ }
857
+ );
858
+ }
859
+ );
860
+ test
861
+ (
862
+ 'reads: get distinct values for a column with filter and pagination',
863
+ function(fDone)
864
+ {
865
+ libSuperTest('http://localhost:9080/')
866
+ .get('1.0/FableTests/Distinct/Type/FilteredTo/FBV~IDAnimal~LT~3/0/1')
867
+ .end(
868
+ function (pError, pResponse)
869
+ {
870
+ var tmpResults = JSON.parse(pResponse.text);
871
+ Expect(tmpResults.length).to.equal(1);
872
+ fDone();
873
+ }
874
+ );
875
+ }
876
+ );
877
+ test
878
+ (
879
+ 'reads: get distinct values for a column with pagination',
880
+ function(fDone)
881
+ {
882
+ libSuperTest('http://localhost:9080/')
883
+ .get('1.0/FableTests/Distinct/Type/2/2')
884
+ .end(
885
+ function (pError, pResponse)
886
+ {
887
+ var tmpResults = JSON.parse(pResponse.text);
888
+ Expect(tmpResults.length).to.equal(2);
889
+ const types = new Set(tmpResults.map((r) => r.Type));
890
+ Expect(types.size).to.equal(2);
891
+ fDone();
892
+ }
893
+ );
894
+ }
895
+ );
896
+ test
823
897
  (
824
898
  'reads: get a filtered paged set of records',
825
899
  function(fDone)
826
900
  {
827
901
  libSuperTest('http://localhost:9080/')
828
- // Get page 2, 2 records per page.
902
+ // Skip one record, 2 records per page.
829
903
  .get('1.0/FableTests/FilteredTo/FBV~Type~EQ~Dog/1/2')
830
904
  .end(
831
905
  function (pError, pResponse)
@@ -1,209 +0,0 @@
1
- From 6a29bd206ef3b9dd8957c532dd8bc10b2c1789ac Mon Sep 17 00:00:00 2001
2
- From: Alex Decker <alex.decker@headlight.com>
3
- Date: Fri, 12 Nov 2021 23:31:24 -0800
4
- Subject: [PATCH 1/2] Don't call response.send on huge record sets. Use
5
- JSONStream instead, to avoid blocking the main thread.
6
-
7
- ---
8
- package.json | 1 +
9
- source/crud/Meadow-Endpoint-BulkCreate.js | 4 ++--
10
- source/crud/Meadow-Endpoint-BulkUpdate.js | 4 ++--
11
- source/crud/Meadow-Endpoint-BulkUpsert.js | 4 ++--
12
- source/crud/Meadow-Endpoint-ReadLiteList.js | 5 +++--
13
- source/crud/Meadow-Endpoint-ReadSelectList.js | 5 +++--
14
- source/crud/Meadow-Endpoint-Reads.js | 6 ++++--
15
- source/crud/Meadow-Endpoint-ReadsBy.js | 5 +++--
16
- test/MeadowEndpoints_basic_tests.js | 5 ++---
17
- 9 files changed, 22 insertions(+), 17 deletions(-)
18
-
19
- diff --git a/package.json b/package.json
20
- index b893e0c..b5bf05f 100644
21
- --- a/package.json
22
- +++ b/package.json
23
- @@ -33,6 +33,7 @@
24
- },
25
- "dependencies": {
26
- "async": "2.6.1",
27
- + "JSONStream": "^1.3.5",
28
- "meadow": "~1.0.30",
29
- "mysql2": "1.6.1",
30
- "orator": "~2.0.2",
31
- diff --git a/source/crud/Meadow-Endpoint-BulkCreate.js b/source/crud/Meadow-Endpoint-BulkCreate.js
32
- index 2858990..eb53ec6 100644
33
- --- a/source/crud/Meadow-Endpoint-BulkCreate.js
34
- +++ b/source/crud/Meadow-Endpoint-BulkCreate.js
35
- @@ -13,6 +13,7 @@
36
- var libAsync = require('async');
37
-
38
- var doCreate = require('./Meadow-Operation-Create.js');
39
- +const streamRecordsToResponse = require('./Meadow-StreamRecordArray');
40
-
41
- var doAPIBulkCreateEndpoint = function(pRequest, pResponse, fNext)
42
- {
43
- @@ -50,8 +51,7 @@ var doAPIBulkCreateEndpoint = function(pRequest, pResponse, fNext)
44
- function(fStageComplete)
45
- {
46
- //5. Respond with the new records
47
- - pResponse.send(pRequest.CreatedRecords);
48
- - return fStageComplete(null);
49
- + return streamRecordsToResponse(pResponse, pRequest.CreatedRecords, fStageComplete);
50
- }
51
- ], function(pError)
52
- {
53
- diff --git a/source/crud/Meadow-Endpoint-BulkUpdate.js b/source/crud/Meadow-Endpoint-BulkUpdate.js
54
- index 95b5a71..cf33e2e 100644
55
- --- a/source/crud/Meadow-Endpoint-BulkUpdate.js
56
- +++ b/source/crud/Meadow-Endpoint-BulkUpdate.js
57
- @@ -13,6 +13,7 @@
58
- var libAsync = require('async');
59
-
60
- var doUpdate = require('./Meadow-Operation-Update.js');
61
- +const streamRecordsToResponse = require('./Meadow-StreamRecordArray');
62
-
63
- var doAPIUpdateEndpoint = function(pRequest, pResponse, fNext)
64
- {
65
- @@ -57,8 +58,7 @@ var doAPIUpdateEndpoint = function(pRequest, pResponse, fNext)
66
- function(fStageComplete)
67
- {
68
- //5. Respond with the new record
69
- - pResponse.send(pRequest.UpdatedRecords);
70
- - return fStageComplete(null);
71
- + return streamRecordsToResponse(pResponse, pRequest.UpdatedRecords, fStageComplete);
72
- }
73
- ], function(pError)
74
- {
75
- diff --git a/source/crud/Meadow-Endpoint-BulkUpsert.js b/source/crud/Meadow-Endpoint-BulkUpsert.js
76
- index e1f7b67..3f8881b 100644
77
- --- a/source/crud/Meadow-Endpoint-BulkUpsert.js
78
- +++ b/source/crud/Meadow-Endpoint-BulkUpsert.js
79
- @@ -14,6 +14,7 @@ var libAsync = require('async');
80
-
81
- var doUpsert = require('./Meadow-Operation-Upsert.js');
82
- var marshalLiteList = require('./Meadow-Marshal-LiteList.js');
83
- +const streamRecordsToResponse = require('./Meadow-StreamRecordArray');
84
-
85
- var doAPIUpsertEndpoint = function(pRequest, pResponse, fNext)
86
- {
87
- @@ -59,8 +60,7 @@ var doAPIUpsertEndpoint = function(pRequest, pResponse, fNext)
88
- function(fStageComplete)
89
- {
90
- //5. Respond with the new records
91
- - pResponse.send(marshalLiteList(pRequest.UpsertedRecords, pRequest));
92
- - return fStageComplete(null);
93
- + return streamRecordsToResponse(pResponse, marshalLiteList(pRequest.UpsertedRecords, pRequest), fStageComplete);
94
- }
95
- ], function(pError)
96
- {
97
- diff --git a/source/crud/Meadow-Endpoint-ReadLiteList.js b/source/crud/Meadow-Endpoint-ReadLiteList.js
98
- index e1113b0..f6837be 100644
99
- --- a/source/crud/Meadow-Endpoint-ReadLiteList.js
100
- +++ b/source/crud/Meadow-Endpoint-ReadLiteList.js
101
- @@ -9,6 +9,8 @@
102
- var libAsync = require('async');
103
- var meadowFilterParser = require('./Meadow-Filter-Parse.js');
104
- var marshalLiteList = require('./Meadow-Marshal-LiteList.js');
105
- +const streamRecordsToResponse = require('./Meadow-StreamRecordArray');
106
- +
107
- /**
108
- * Get a set of records from a DAL.
109
- */
110
- @@ -123,8 +125,7 @@ var doAPIReadLiteEndpoint = function(pRequest, pResponse, fNext)
111
- }
112
-
113
- pRequest.CommonServices.log.info('Read a recordset lite list with '+pResultRecords.length+' results.', {SessionID:pRequest.UserSession.SessionID, RequestID:pRequest.RequestUUID, RequestURL:pRequest.url, Action:pRequest.DAL.scope+'-ReadLite'}, pRequest);
114
- - pResponse.send(pResultRecords);
115
- - return fNext();
116
- + return streamRecordsToResponse(pResponse, pResultRecords, fNext);
117
- }
118
- );
119
- };
120
- diff --git a/source/crud/Meadow-Endpoint-ReadSelectList.js b/source/crud/Meadow-Endpoint-ReadSelectList.js
121
- index d41580d..5402a35 100644
122
- --- a/source/crud/Meadow-Endpoint-ReadSelectList.js
123
- +++ b/source/crud/Meadow-Endpoint-ReadSelectList.js
124
- @@ -8,6 +8,8 @@
125
- */
126
- var libAsync = require('async');
127
- var meadowFilterParser = require('./Meadow-Filter-Parse.js');
128
- +const streamRecordsToResponse = require('./Meadow-StreamRecordArray');
129
- +
130
- /**
131
- * Get a set of records from a DAL.
132
- */
133
- @@ -130,8 +132,7 @@ var doAPIReadSelectListEndpoint = function(pRequest, pResponse, fNext)
134
- }
135
-
136
- pRequest.CommonServices.log.info('Read a recordset select list with '+pResultRecords.length+' results.', {SessionID:pRequest.UserSession.SessionID, RequestID:pRequest.RequestUUID, RequestURL:pRequest.url, Action:pRequest.DAL.scope+'-ReadSelectList'}, pRequest);
137
- - pResponse.send(pResultRecords);
138
- - return fNext();
139
- + return streamRecordsToResponse(pResponse, pResultRecords, fNext);
140
- }
141
- );
142
- };
143
- diff --git a/source/crud/Meadow-Endpoint-Reads.js b/source/crud/Meadow-Endpoint-Reads.js
144
- index 49cc779..669441f 100644
145
- --- a/source/crud/Meadow-Endpoint-Reads.js
146
- +++ b/source/crud/Meadow-Endpoint-Reads.js
147
- @@ -8,6 +8,8 @@
148
- */
149
- var libAsync = require('async');
150
- var meadowFilterParser = require('./Meadow-Filter-Parse.js');
151
- +const streamRecordsToResponse = require('./Meadow-StreamRecordArray');
152
- +
153
- /**
154
- * Get a set of records from a DAL.
155
- */
156
- @@ -113,8 +115,8 @@ var doAPIReadsEndpoint = function(pRequest, pResponse, fNext)
157
- }
158
-
159
- pRequest.CommonServices.log.info('Read a list of records.', {SessionID:pRequest.UserSession.SessionID, RequestID:pRequest.RequestUUID, RequestURL:pRequest.url, Action:pRequest.DAL.scope+'-Reads'}, pRequest);
160
- - pResponse.send(pRequest.Records);
161
- - return fNext();
162
- +
163
- + streamRecordsToResponse(pResponse, pRequest.Records, fNext);
164
- }
165
- );
166
- };
167
- diff --git a/source/crud/Meadow-Endpoint-ReadsBy.js b/source/crud/Meadow-Endpoint-ReadsBy.js
168
- index 36a5397..b7c5deb 100644
169
- --- a/source/crud/Meadow-Endpoint-ReadsBy.js
170
- +++ b/source/crud/Meadow-Endpoint-ReadsBy.js
171
- @@ -7,6 +7,8 @@
172
- * @module Meadow
173
- */
174
- var libAsync = require('async');
175
- +const streamRecordsToResponse = require('./Meadow-StreamRecordArray');
176
- +
177
- /**
178
- * Get a specific record from a DAL.
179
- */
180
- @@ -140,8 +142,7 @@ var doAPIReadsByEndpoint = function(pRequest, pResponse, fNext)
181
- }
182
-
183
- pRequest.CommonServices.log.info('Read a list of records by '+pRequest.params.ByField+' = '+pRequest.params.ByValue+'.', {SessionID:pRequest.UserSession.SessionID, RequestID:pRequest.RequestUUID, RequestURL:pRequest.url, Action:pRequest.DAL.scope+'-ReadsBy'}, pRequest);
184
- - pResponse.send(pRequest.Records);
185
- - return fNext();
186
- + return streamRecordsToResponse(pResponse, pRequest.Records, fNext);
187
- }
188
- );
189
- };
190
- diff --git a/test/MeadowEndpoints_basic_tests.js b/test/MeadowEndpoints_basic_tests.js
191
- index ac40dcc..02944db 100644
192
- --- a/test/MeadowEndpoints_basic_tests.js
193
- +++ b/test/MeadowEndpoints_basic_tests.js
194
- @@ -736,10 +736,9 @@ suite
195
- .end(
196
- function (pError, pResponse)
197
- {
198
- - console.log('FUCK'+pResponse.text)
199
- var tmpResults = JSON.parse(pResponse.text);
200
- - Expect(tmpResults.length).to.equal(6);
201
- - Expect(tmpResults[0].Value).to.equal('FableTest #1');
202
- + Expect(tmpResults.length).to.equal(2);
203
- + Expect(tmpResults[0].Value).to.equal('FableTest #3');
204
- fDone();
205
- }
206
- );
207
- --
208
- 2.25.1
209
-
@@ -1,38 +0,0 @@
1
- From 6e13b744340cf152a393614188673e65f45d963b Mon Sep 17 00:00:00 2001
2
- From: Alex Decker <alex.decker@headlight.com>
3
- Date: Fri, 24 Sep 2021 17:16:18 -0700
4
- Subject: [PATCH 1/3] Register wildcard matches that have parameter-count
5
- matches afterward, so the exact match is used.
6
-
7
- ---
8
- source/Meadow-Endpoints.js | 6 +++---
9
- 1 file changed, 3 insertions(+), 3 deletions(-)
10
-
11
- diff --git a/source/Meadow-Endpoints.js b/source/Meadow-Endpoints.js
12
- index ec6c5df..288cda9 100644
13
- --- a/source/Meadow-Endpoints.js
14
- +++ b/source/Meadow-Endpoints.js
15
- @@ -342,17 +342,17 @@ var MeadowEndpoints = function()
16
- pRestServer.get('/1.0/'+tmpEndpointName+'s/FilteredTo/:Filter', _EndpointAuthenticators.Reads, wireState, _Endpoints.Reads);
17
- pRestServer.get('/1.0/'+tmpEndpointName+'s/FilteredTo/:Filter/:Begin/:Cap', _EndpointAuthenticators.Reads, wireState, _Endpoints.Reads);
18
- pRestServer.get('/1.0/'+tmpEndpointName+'Select', _EndpointAuthenticators.Reads, wireState, _Endpoints.ReadSelectList);
19
- - pRestServer.get('/1.0/'+tmpEndpointName+'Select/:Begin/:Cap', _EndpointAuthenticators.Reads, wireState, _Endpoints.ReadSelectList);
20
- pRestServer.get('/1.0/'+tmpEndpointName+'Select/FilteredTo/:Filter', _EndpointAuthenticators.Reads, wireState, _Endpoints.ReadSelectList);
21
- pRestServer.get('/1.0/'+tmpEndpointName+'Select/FilteredTo/:Filter/:Begin/:Cap', _EndpointAuthenticators.Reads, wireState, _Endpoints.ReadSelectList);
22
- + pRestServer.get('/1.0/'+tmpEndpointName+'Select/:Begin/:Cap', _EndpointAuthenticators.Reads, wireState, _Endpoints.ReadSelectList);
23
- pRestServer.get('/1.0/'+tmpEndpointName+'s/Lite', _EndpointAuthenticators.Reads, wireState, _Endpoints.ReadLiteList);
24
- - pRestServer.get('/1.0/'+tmpEndpointName+'s/Lite/:Begin/:Cap', _EndpointAuthenticators.Reads, wireState, _Endpoints.ReadLiteList);
25
- pRestServer.get('/1.0/'+tmpEndpointName+'s/Lite/FilteredTo/:Filter', _EndpointAuthenticators.Reads, wireState, _Endpoints.ReadLiteList);
26
- pRestServer.get('/1.0/'+tmpEndpointName+'s/Lite/FilteredTo/:Filter/:Begin/:Cap', _EndpointAuthenticators.Reads, wireState, _Endpoints.ReadLiteList);
27
- + pRestServer.get('/1.0/'+tmpEndpointName+'s/Lite/:Begin/:Cap', _EndpointAuthenticators.Reads, wireState, _Endpoints.ReadLiteList);
28
- pRestServer.get('/1.0/'+tmpEndpointName+'s/LiteExtended/:ExtraColumns', _EndpointAuthenticators.Reads, wireState, _Endpoints.ReadLiteList);
29
- - pRestServer.get('/1.0/'+tmpEndpointName+'s/LiteExtended/:ExtraColumns/:Begin/:Cap', _EndpointAuthenticators.Reads, wireState, _Endpoints.ReadLiteList);
30
- pRestServer.get('/1.0/'+tmpEndpointName+'s/LiteExtended/:ExtraColumns/FilteredTo/:Filter', _EndpointAuthenticators.Reads, wireState, _Endpoints.ReadLiteList);
31
- pRestServer.get('/1.0/'+tmpEndpointName+'s/LiteExtended/:ExtraColumns/FilteredTo/:Filter/:Begin/:Cap', _EndpointAuthenticators.Reads, wireState, _Endpoints.ReadLiteList);
32
- + pRestServer.get('/1.0/'+tmpEndpointName+'s/LiteExtended/:ExtraColumns/:Begin/:Cap', _EndpointAuthenticators.Reads, wireState, _Endpoints.ReadLiteList);
33
- pRestServer.get('/1.0/'+tmpEndpointName+'s/:Begin/:Cap', _EndpointAuthenticators.Reads, wireState, _Endpoints.Reads);
34
- }
35
- if (_EnabledBehaviors.Update)
36
- --
37
- 2.25.1
38
-
@@ -1,24 +0,0 @@
1
- From 80e05ff43891942bfdcebe03a3680402bfc627a4 Mon Sep 17 00:00:00 2001
2
- From: Alex Decker <alex.decker@headlight.com>
3
- Date: Fri, 12 Nov 2021 23:31:42 -0800
4
- Subject: [PATCH 2/2] Bump package version.
5
-
6
- ---
7
- package.json | 2 +-
8
- 1 file changed, 1 insertion(+), 1 deletion(-)
9
-
10
- diff --git a/package.json b/package.json
11
- index b5bf05f..c55df53 100644
12
- --- a/package.json
13
- +++ b/package.json
14
- @@ -1,6 +1,6 @@
15
- {
16
- "name": "meadow-endpoints",
17
- - "version": "2.0.11",
18
- + "version": "2.0.12",
19
- "description": "Automatic API endpoints for Meadow data.",
20
- "main": "source/Meadow-Endpoints.js",
21
- "scripts": {
22
- --
23
- 2.25.1
24
-
@@ -1,47 +0,0 @@
1
- From f45d012b61f34ba52756cfb52ab0b66158493973 Mon Sep 17 00:00:00 2001
2
- From: Alex Decker <alex.decker@headlight.com>
3
- Date: Fri, 24 Sep 2021 17:17:19 -0700
4
- Subject: [PATCH 2/3] Fix indent.
5
-
6
- ---
7
- source/Meadow-Endpoints.js | 18 +++++++++---------
8
- 1 file changed, 9 insertions(+), 9 deletions(-)
9
-
10
- diff --git a/source/Meadow-Endpoints.js b/source/Meadow-Endpoints.js
11
- index 288cda9..2d1204e 100644
12
- --- a/source/Meadow-Endpoints.js
13
- +++ b/source/Meadow-Endpoints.js
14
- @@ -357,21 +357,21 @@ var MeadowEndpoints = function()
15
- }
16
- if (_EnabledBehaviors.Update)
17
- {
18
- - pRestServer.put('/1.0/'+tmpEndpointName, _CommonServices.bodyParser(), _EndpointAuthenticators.Update, wireState, _Endpoints.Update);
19
- - pRestServer.put('/1.0/'+tmpEndpointName+'s', _CommonServices.bodyParser(), _EndpointAuthenticators.Update, wireState, _Endpoints.Updates);
20
- - pRestServer.put('/1.0/'+tmpEndpointName+'/Upsert', _CommonServices.bodyParser(), _EndpointAuthenticators.Update, wireState, _Endpoints.Upsert);
21
- - pRestServer.put('/1.0/'+tmpEndpointName+'/Upserts', _CommonServices.bodyParser(), _EndpointAuthenticators.Update, wireState, _Endpoints.Upserts);
22
- + pRestServer.put('/1.0/'+tmpEndpointName, _CommonServices.bodyParser(), _EndpointAuthenticators.Update, wireState, _Endpoints.Update);
23
- + pRestServer.put('/1.0/'+tmpEndpointName+'s', _CommonServices.bodyParser(), _EndpointAuthenticators.Update, wireState, _Endpoints.Updates);
24
- + pRestServer.put('/1.0/'+tmpEndpointName+'/Upsert', _CommonServices.bodyParser(), _EndpointAuthenticators.Update, wireState, _Endpoints.Upsert);
25
- + pRestServer.put('/1.0/'+tmpEndpointName+'/Upserts', _CommonServices.bodyParser(), _EndpointAuthenticators.Update, wireState, _Endpoints.Upserts);
26
- }
27
- if (_EnabledBehaviors.Delete)
28
- {
29
- - pRestServer.del('/1.0/'+tmpEndpointName, _CommonServices.bodyParser(), _EndpointAuthenticators.Delete, wireState, _Endpoints.Delete);
30
- - pRestServer.del('/1.0/'+tmpEndpointName+'/:IDRecord', _EndpointAuthenticators.Delete, wireState, _Endpoints.Delete);
31
- + pRestServer.del('/1.0/'+tmpEndpointName, _CommonServices.bodyParser(), _EndpointAuthenticators.Delete, wireState, _Endpoints.Delete);
32
- + pRestServer.del('/1.0/'+tmpEndpointName+'/:IDRecord', _EndpointAuthenticators.Delete, wireState, _Endpoints.Delete);
33
- }
34
- if (_EnabledBehaviors.Count)
35
- {
36
- - pRestServer.get('/1.0/'+tmpEndpointName+'s/Count', _EndpointAuthenticators.Count, wireState, _Endpoints.Count);
37
- - pRestServer.get('/1.0/'+tmpEndpointName+'s/Count/By/:ByField/:ByValue', _EndpointAuthenticators.Count, wireState, _Endpoints.CountBy);
38
- - pRestServer.get('/1.0/'+tmpEndpointName+'s/Count/FilteredTo/:Filter', _EndpointAuthenticators.Count, wireState, _Endpoints.Count);
39
- + pRestServer.get('/1.0/'+tmpEndpointName+'s/Count', _EndpointAuthenticators.Count, wireState, _Endpoints.Count);
40
- + pRestServer.get('/1.0/'+tmpEndpointName+'s/Count/By/:ByField/:ByValue', _EndpointAuthenticators.Count, wireState, _Endpoints.CountBy);
41
- + pRestServer.get('/1.0/'+tmpEndpointName+'s/Count/FilteredTo/:Filter', _EndpointAuthenticators.Count, wireState, _Endpoints.Count);
42
- }
43
- };
44
-
45
- --
46
- 2.25.1
47
-
@@ -1,24 +0,0 @@
1
- From f15fe4fa2611ca3cbec3c78ba819bca746b1d917 Mon Sep 17 00:00:00 2001
2
- From: Alex Decker <alex.decker@headlight.com>
3
- Date: Fri, 24 Sep 2021 17:18:12 -0700
4
- Subject: [PATCH 3/3] Bump package version for publication.
5
-
6
- ---
7
- package.json | 2 +-
8
- 1 file changed, 1 insertion(+), 1 deletion(-)
9
-
10
- diff --git a/package.json b/package.json
11
- index 84dace7..b893e0c 100644
12
- --- a/package.json
13
- +++ b/package.json
14
- @@ -1,6 +1,6 @@
15
- {
16
- "name": "meadow-endpoints",
17
- - "version": "2.0.10",
18
- + "version": "2.0.11",
19
- "description": "Automatic API endpoints for Meadow data.",
20
- "main": "source/Meadow-Endpoints.js",
21
- "scripts": {
22
- --
23
- 2.25.1
24
-
@@ -1,206 +0,0 @@
1
- /**
2
- * Meadow Endpoint Utility Function - 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
-
41
- This means: FBV~Category~EQ~Books~FBV~PublishedYear~GT~2000~FSF~PublishedYear~DESC~0
42
- Filters down to ALL BOOKS PUBLUSHED AFTER 200 IN DESCENDING ORDER
43
- */
44
-
45
- // Get the comparison operator for use in a query stanza
46
- var getFilterComparisonOperator = function(pFilterOperator)
47
- {
48
- var tmpOperator = '=';
49
- switch(pFilterOperator)
50
- {
51
- case 'EQ':
52
- tmpOperator = '=';
53
- break;
54
- case 'NE':
55
- tmpOperator = '!=';
56
- break;
57
- case 'GT':
58
- tmpOperator = '>';
59
- break;
60
- case 'GE':
61
- tmpOperator = '>=';
62
- break;
63
- case 'LT':
64
- tmpOperator = '<';
65
- break;
66
- case 'LE':
67
- tmpOperator = '<=';
68
- break;
69
- case 'LK':
70
- tmpOperator = 'LIKE';
71
- break;
72
- case 'NLK':
73
- tmpOperator = 'NOT LIKE';
74
- break;
75
- case 'IN':
76
- tmpOperator = 'IS NULL';
77
- break;
78
- case 'NN':
79
- tmpOperator = 'IS NOT NULL';
80
- break;
81
- case 'INN':
82
- tmpOperator = 'IN';
83
- break;
84
- case 'FOP':
85
- tmpOperator = '(';
86
- break;
87
- case 'FCP':
88
- tmpOperator = ')';
89
- break;
90
- }
91
- return tmpOperator;
92
- };
93
-
94
- var addFilterStanzaToQuery = function(pFilterStanza, pQuery)
95
- {
96
- if (!pFilterStanza.Instruction)
97
- {
98
- return false;
99
- }
100
-
101
- switch(pFilterStanza.Instruction)
102
- {
103
- case 'FBV': // Filter by Value (left-side AND)
104
- pQuery.addFilter(pFilterStanza.Field, pFilterStanza.Value, getFilterComparisonOperator(pFilterStanza.Operator), 'AND');
105
- break;
106
-
107
- case 'FBVOR': // Filter by Value (left-side OR)
108
- pQuery.addFilter(pFilterStanza.Field, pFilterStanza.Value, getFilterComparisonOperator(pFilterStanza.Operator), 'OR');
109
- break;
110
-
111
- case 'FBL': // Filter by List (left-side AND)
112
- // Just split the value by comma for now. May want to revisit better characters or techniques later.
113
- pQuery.addFilter(pFilterStanza.Field, pFilterStanza.Value.split(','), getFilterComparisonOperator(pFilterStanza.Operator), 'AND');
114
- break;
115
-
116
- case 'FBLOR': // Filter by List (left-side OR)
117
- // Just split the value by comma for now. May want to revisit better characters or techniques later.
118
- pQuery.addFilter(pFilterStanza.Field, pFilterStanza.Value.split(','), getFilterComparisonOperator(pFilterStanza.Operator, 'OR'));
119
- break;
120
-
121
- case 'FBD': // Filter by Date (exclude time)
122
- pQuery.addFilter(`DATE(${pFilterStanza.Field})`, pFilterStanza.Value.split(','), getFilterComparisonOperator(pFilterStanza.Operator), 'AND', pFilterStanza.Field);
123
- break;
124
-
125
- case 'FBDOR': // Filter by Date (exclude time)
126
- pQuery.addFilter(`DATE(${pFilterStanza.Field})`, pFilterStanza.Value.split(','), getFilterComparisonOperator(pFilterStanza.Operator), 'OR', pFilterStanza.Field);
127
- break;
128
-
129
- case 'FSF': // Filter Sort Field
130
- var tmpSortDirection = (pFilterStanza.Operator === 'DESC') ? 'Descending' : 'Ascending';
131
- pQuery.addSort({Column:pFilterStanza.Field, Direction:tmpSortDirection});
132
- break;
133
-
134
- case 'FOP': // Filter Open Paren
135
- pQuery.addFilter('', '', '(');
136
- break;
137
-
138
- case 'FCP': // Filter Close Paren
139
- pQuery.addFilter('', '', ')');
140
- break;
141
-
142
-
143
- default:
144
- //console.log('Unparsable filter stanza.');
145
- return false;
146
- break;
147
- }
148
-
149
- // Be paranoid about the instruction
150
- pFilterStanza.Instruction = false;
151
- return true;
152
- };
153
-
154
- var doParseFilter = function(pFilterString, pQuery)
155
- {
156
- if (typeof(pFilterString) !== 'string')
157
- {
158
- return false;
159
- }
160
-
161
- var tmpFilterTerms = pFilterString.split('~');
162
-
163
- if (tmpFilterTerms.length < 4)
164
- return true;
165
-
166
- var tmpFilterStanza = { Instruction:false };
167
-
168
- for (var i = 0; i < tmpFilterTerms.length; i++)
169
- {
170
- switch(i % 4)
171
- {
172
- case 0: // INSTRUCTION
173
- addFilterStanzaToQuery(tmpFilterStanza, pQuery);
174
- //console.log(i+' Instruction: '+tmpFilterTerms[i]);
175
- tmpFilterStanza = (
176
- {
177
- Instruction: tmpFilterTerms[i],
178
- Field: '',
179
- Operator: '',
180
- Value: ''
181
- });
182
- break;
183
-
184
- case 1: // FIELD
185
- //console.log(i+' Field: '+tmpFilterTerms[i]);
186
- tmpFilterStanza.Field = tmpFilterTerms[i];
187
- break;
188
-
189
- case 2: // OPERATOR
190
- //console.log(i+' Operator: '+tmpFilterTerms[i]);
191
- tmpFilterStanza.Operator = tmpFilterTerms[i];
192
- break;
193
-
194
- case 3: // VALUE
195
- //console.log(i+' Value: '+tmpFilterTerms[i]);
196
- tmpFilterStanza.Value = tmpFilterTerms[i];
197
- break;
198
- }
199
- }
200
-
201
- addFilterStanzaToQuery(tmpFilterStanza, pQuery);
202
-
203
- return true;
204
- };
205
-
206
- module.exports = doParseFilter;