meadow-endpoints 2.0.11 → 2.0.14
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 +5 -3
- package/source/Meadow-Endpoints.js +49 -38
- package/source/crud/Meadow-Endpoint-BulkCreate.js +2 -2
- package/source/crud/Meadow-Endpoint-BulkUpdate.js +2 -2
- package/source/crud/Meadow-Endpoint-BulkUpsert.js +2 -2
- package/source/crud/Meadow-Endpoint-Count.js +1 -1
- package/source/crud/Meadow-Endpoint-ReadDistinctList.js +146 -0
- package/source/crud/Meadow-Endpoint-ReadLiteList.js +11 -4
- package/source/crud/Meadow-Endpoint-ReadSelectList.js +9 -3
- package/source/crud/Meadow-Endpoint-Reads.js +10 -3
- package/source/crud/Meadow-Endpoint-ReadsBy.js +8 -2
- package/source/crud/Meadow-Marshal-DistinctList.js +55 -0
- package/source/crud/Meadow-StreamRecordArray.js +45 -0
- package/test/MeadowEndpoints_basic_tests.js +79 -6
- package/0001-Register-wildcard-matches-that-have-parameter-count-.patch +0 -38
- package/0002-Fix-indent.patch +0 -47
- package/0003-Bump-package-version-for-publication.patch +0 -24
- package/source/crud/Meadow-Filter-Parse.js +0 -206
package/package.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "meadow-endpoints",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.14",
|
|
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
|
|
9
|
+
"test": "./node_modules/.bin/mocha --exit -u tdd -R spec"
|
|
10
10
|
},
|
|
11
11
|
"repository": {
|
|
12
12
|
"type": "git",
|
|
@@ -33,7 +33,9 @@
|
|
|
33
33
|
},
|
|
34
34
|
"dependencies": {
|
|
35
35
|
"async": "2.6.1",
|
|
36
|
-
"
|
|
36
|
+
"JSONStream": "^1.3.5",
|
|
37
|
+
"meadow": "~1.0.32",
|
|
38
|
+
"meadow-filter": "^1.0.1",
|
|
37
39
|
"mysql2": "1.6.1",
|
|
38
40
|
"orator": "~2.0.2",
|
|
39
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
|
-
|
|
298
|
+
const tmpEndpointVersion = _Fable.settings.MeadowEndpointVersion || '1.0';
|
|
294
299
|
// TODO: Allow the user to override the endpoint "name" eventually.
|
|
295
|
-
|
|
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(
|
|
320
|
+
pRestServer.get(`${tmpEndpointPrefix}/Schema`, _EndpointAuthenticators.Schema, wireState, _Endpoints.Schema);
|
|
314
321
|
}
|
|
315
322
|
if (_EnabledBehaviors.New)
|
|
316
323
|
{
|
|
317
|
-
pRestServer.get(
|
|
324
|
+
pRestServer.get(`${tmpEndpointPrefix}/Schema/New`, _EndpointAuthenticators.New, wireState, _Endpoints.New);
|
|
318
325
|
}
|
|
319
326
|
if (_EnabledBehaviors.Validate)
|
|
320
327
|
{
|
|
321
|
-
pRestServer.post(
|
|
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(
|
|
330
|
-
pRestServer.post(
|
|
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(
|
|
335
|
-
pRestServer.get(
|
|
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(
|
|
340
|
-
pRestServer.get(
|
|
341
|
-
pRestServer.get(
|
|
342
|
-
pRestServer.get(
|
|
343
|
-
pRestServer.get(
|
|
344
|
-
pRestServer.get(
|
|
345
|
-
pRestServer.get(
|
|
346
|
-
pRestServer.get(
|
|
347
|
-
pRestServer.get(
|
|
348
|
-
pRestServer.get(
|
|
349
|
-
pRestServer.get(
|
|
350
|
-
pRestServer.get(
|
|
351
|
-
pRestServer.get(
|
|
352
|
-
pRestServer.get(
|
|
353
|
-
pRestServer.get(
|
|
354
|
-
pRestServer.get(
|
|
355
|
-
pRestServer.get(
|
|
356
|
-
pRestServer.get(
|
|
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(
|
|
361
|
-
pRestServer.put(
|
|
362
|
-
pRestServer.put(
|
|
363
|
-
pRestServer.put(
|
|
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(
|
|
368
|
-
pRestServer.del(
|
|
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(
|
|
373
|
-
pRestServer.get(
|
|
374
|
-
pRestServer.get(
|
|
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(
|
|
507
|
+
parseFilter: require('meadow-filter').parse,
|
|
497
508
|
|
|
498
509
|
// Expose the DAL
|
|
499
510
|
DAL: _Meadow,
|
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
var libAsync = require('async');
|
|
14
14
|
|
|
15
15
|
var doCreate = require('./Meadow-Operation-Create.js');
|
|
16
|
+
const streamRecordsToResponse = require('./Meadow-StreamRecordArray');
|
|
16
17
|
|
|
17
18
|
var doAPIBulkCreateEndpoint = function(pRequest, pResponse, fNext)
|
|
18
19
|
{
|
|
@@ -50,8 +51,7 @@ var doAPIBulkCreateEndpoint = function(pRequest, pResponse, fNext)
|
|
|
50
51
|
function(fStageComplete)
|
|
51
52
|
{
|
|
52
53
|
//5. Respond with the new records
|
|
53
|
-
pResponse
|
|
54
|
-
return fStageComplete(null);
|
|
54
|
+
return streamRecordsToResponse(pResponse, pRequest.CreatedRecords, fStageComplete);
|
|
55
55
|
}
|
|
56
56
|
], function(pError)
|
|
57
57
|
{
|
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
var libAsync = require('async');
|
|
14
14
|
|
|
15
15
|
var doUpdate = require('./Meadow-Operation-Update.js');
|
|
16
|
+
const streamRecordsToResponse = require('./Meadow-StreamRecordArray');
|
|
16
17
|
|
|
17
18
|
var doAPIUpdateEndpoint = function(pRequest, pResponse, fNext)
|
|
18
19
|
{
|
|
@@ -57,8 +58,7 @@ var doAPIUpdateEndpoint = function(pRequest, pResponse, fNext)
|
|
|
57
58
|
function(fStageComplete)
|
|
58
59
|
{
|
|
59
60
|
//5. Respond with the new record
|
|
60
|
-
pResponse
|
|
61
|
-
return fStageComplete(null);
|
|
61
|
+
return streamRecordsToResponse(pResponse, pRequest.UpdatedRecords, fStageComplete);
|
|
62
62
|
}
|
|
63
63
|
], function(pError)
|
|
64
64
|
{
|
|
@@ -14,6 +14,7 @@ var libAsync = require('async');
|
|
|
14
14
|
|
|
15
15
|
var doUpsert = require('./Meadow-Operation-Upsert.js');
|
|
16
16
|
var marshalLiteList = require('./Meadow-Marshal-LiteList.js');
|
|
17
|
+
const streamRecordsToResponse = require('./Meadow-StreamRecordArray');
|
|
17
18
|
|
|
18
19
|
var doAPIUpsertEndpoint = function(pRequest, pResponse, fNext)
|
|
19
20
|
{
|
|
@@ -59,8 +60,7 @@ var doAPIUpsertEndpoint = function(pRequest, pResponse, fNext)
|
|
|
59
60
|
function(fStageComplete)
|
|
60
61
|
{
|
|
61
62
|
//5. Respond with the new records
|
|
62
|
-
pResponse
|
|
63
|
-
return fStageComplete(null);
|
|
63
|
+
return streamRecordsToResponse(pResponse, marshalLiteList(pRequest.UpsertedRecords, pRequest), fStageComplete);
|
|
64
64
|
}
|
|
65
65
|
], function(pError)
|
|
66
66
|
{
|
|
@@ -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,8 +7,10 @@
|
|
|
7
7
|
* @module Meadow
|
|
8
8
|
*/
|
|
9
9
|
var libAsync = require('async');
|
|
10
|
-
|
|
10
|
+
const meadowFilterParser = require('meadow-filter').parse;
|
|
11
11
|
var marshalLiteList = require('./Meadow-Marshal-LiteList.js');
|
|
12
|
+
const streamRecordsToResponse = require('./Meadow-StreamRecordArray');
|
|
13
|
+
|
|
12
14
|
/**
|
|
13
15
|
* Get a set of records from a DAL.
|
|
14
16
|
*/
|
|
@@ -69,6 +71,11 @@ var doAPIReadLiteEndpoint = function(pRequest, pResponse, fNext)
|
|
|
69
71
|
{
|
|
70
72
|
pRequest.BehaviorModifications.runBehavior('Reads-QueryConfiguration', pRequest, fStageComplete);
|
|
71
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
|
+
},
|
|
72
79
|
// 1c. Do the record read
|
|
73
80
|
function (fStageComplete)
|
|
74
81
|
{
|
|
@@ -90,7 +97,8 @@ var doAPIReadLiteEndpoint = function(pRequest, pResponse, fNext)
|
|
|
90
97
|
// 2.5: Check if there is an authorizer set for this endpoint and user role combination, and authorize based on that
|
|
91
98
|
function (fStageComplete)
|
|
92
99
|
{
|
|
93
|
-
|
|
100
|
+
// shared permission with reads
|
|
101
|
+
pRequest.Authorizers.authorizeRequest('Reads', pRequest, fStageComplete);
|
|
94
102
|
},
|
|
95
103
|
// 2.6: Check if authorization or post processing denied security access to the record
|
|
96
104
|
function (fStageComplete)
|
|
@@ -123,8 +131,7 @@ var doAPIReadLiteEndpoint = function(pRequest, pResponse, fNext)
|
|
|
123
131
|
}
|
|
124
132
|
|
|
125
133
|
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);
|
|
126
|
-
pResponse
|
|
127
|
-
return fNext();
|
|
134
|
+
return streamRecordsToResponse(pResponse, pResultRecords, fNext);
|
|
128
135
|
}
|
|
129
136
|
);
|
|
130
137
|
};
|
|
@@ -7,7 +7,9 @@
|
|
|
7
7
|
* @module Meadow
|
|
8
8
|
*/
|
|
9
9
|
var libAsync = require('async');
|
|
10
|
-
|
|
10
|
+
const meadowFilterParser = require('meadow-filter').parse;
|
|
11
|
+
const streamRecordsToResponse = require('./Meadow-StreamRecordArray');
|
|
12
|
+
|
|
11
13
|
/**
|
|
12
14
|
* Get a set of records from a DAL.
|
|
13
15
|
*/
|
|
@@ -64,6 +66,11 @@ var doAPIReadSelectListEndpoint = function(pRequest, pResponse, fNext)
|
|
|
64
66
|
{
|
|
65
67
|
pRequest.BehaviorModifications.runBehavior('Reads-QueryConfiguration', pRequest, fStageComplete);
|
|
66
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
|
+
},
|
|
67
74
|
// 1c. Do the record read
|
|
68
75
|
function (fStageComplete)
|
|
69
76
|
{
|
|
@@ -130,8 +137,7 @@ var doAPIReadSelectListEndpoint = function(pRequest, pResponse, fNext)
|
|
|
130
137
|
}
|
|
131
138
|
|
|
132
139
|
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);
|
|
133
|
-
pResponse
|
|
134
|
-
return fNext();
|
|
140
|
+
return streamRecordsToResponse(pResponse, pResultRecords, fNext);
|
|
135
141
|
}
|
|
136
142
|
);
|
|
137
143
|
};
|
|
@@ -7,7 +7,9 @@
|
|
|
7
7
|
* @module Meadow
|
|
8
8
|
*/
|
|
9
9
|
var libAsync = require('async');
|
|
10
|
-
|
|
10
|
+
const meadowFilterParser = require('meadow-filter').parse;
|
|
11
|
+
const streamRecordsToResponse = require('./Meadow-StreamRecordArray');
|
|
12
|
+
|
|
11
13
|
/**
|
|
12
14
|
* Get a set of records from a DAL.
|
|
13
15
|
*/
|
|
@@ -65,6 +67,11 @@ var doAPIReadsEndpoint = function(pRequest, pResponse, fNext)
|
|
|
65
67
|
{
|
|
66
68
|
pRequest.BehaviorModifications.runBehavior('Reads-QueryConfiguration', pRequest, fStageComplete);
|
|
67
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
|
+
},
|
|
68
75
|
// 3. Execute the query
|
|
69
76
|
function (fStageComplete)
|
|
70
77
|
{
|
|
@@ -113,8 +120,8 @@ var doAPIReadsEndpoint = function(pRequest, pResponse, fNext)
|
|
|
113
120
|
}
|
|
114
121
|
|
|
115
122
|
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);
|
|
116
|
-
|
|
117
|
-
|
|
123
|
+
|
|
124
|
+
streamRecordsToResponse(pResponse, pRequest.Records, fNext);
|
|
118
125
|
}
|
|
119
126
|
);
|
|
120
127
|
};
|
|
@@ -7,6 +7,8 @@
|
|
|
7
7
|
* @module Meadow
|
|
8
8
|
*/
|
|
9
9
|
var libAsync = require('async');
|
|
10
|
+
const streamRecordsToResponse = require('./Meadow-StreamRecordArray');
|
|
11
|
+
|
|
10
12
|
/**
|
|
11
13
|
* Get a specific record from a DAL.
|
|
12
14
|
*/
|
|
@@ -92,6 +94,11 @@ var doAPIReadsByEndpoint = function(pRequest, pResponse, fNext)
|
|
|
92
94
|
{
|
|
93
95
|
pRequest.BehaviorModifications.runBehavior('Reads-QueryConfiguration', pRequest, fStageComplete);
|
|
94
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
|
+
},
|
|
95
102
|
// 4. Execute the query
|
|
96
103
|
function (fStageComplete)
|
|
97
104
|
{
|
|
@@ -140,8 +147,7 @@ var doAPIReadsByEndpoint = function(pRequest, pResponse, fNext)
|
|
|
140
147
|
}
|
|
141
148
|
|
|
142
149
|
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);
|
|
143
|
-
pResponse
|
|
144
|
-
return fNext();
|
|
150
|
+
return streamRecordsToResponse(pResponse, pRequest.Records, fNext);
|
|
145
151
|
}
|
|
146
152
|
);
|
|
147
153
|
};
|
|
@@ -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;
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Meadow Endpoint Marshaller - Stream an array of recods as JSON to an output stream.
|
|
3
|
+
*
|
|
4
|
+
* If the array is small enough, we just call send() for simplicity.
|
|
5
|
+
*
|
|
6
|
+
* @license MIT
|
|
7
|
+
*
|
|
8
|
+
* @author Alex Decker <alex.decker@headlight.com>
|
|
9
|
+
* @module Meadow
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
const libAsync = require('async');
|
|
13
|
+
const JSONStream = require('JSONStream');
|
|
14
|
+
const libUnderscore = require('underscore');
|
|
15
|
+
|
|
16
|
+
module.exports = (pResponse, pRecords, fCallback) =>
|
|
17
|
+
{
|
|
18
|
+
// for meadow invoke, writeHead isn't provided, so just call send(), which is the shim it uses...
|
|
19
|
+
// also, for small arrays, don't bother with the async serialization; this threshold could use tuning
|
|
20
|
+
if (!pResponse.writeHead || !Array.isArray(pRecords) || pRecords.length < 2500)
|
|
21
|
+
{
|
|
22
|
+
pResponse.send(pRecords);
|
|
23
|
+
return fCallback();
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
pResponse.writeHead(200,
|
|
27
|
+
{
|
|
28
|
+
'content-type': 'application/json',
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
const recordJsonMarshaller = JSONStream.stringify();
|
|
32
|
+
recordJsonMarshaller.pipe(pResponse);
|
|
33
|
+
|
|
34
|
+
// we write the records in chunks; doing one per loop is very inefficient, doing all is the same as not doing this at all
|
|
35
|
+
libAsync.eachSeries(libUnderscore.chunk(pRecords, 1000), (pRecordChunk, fNext) =>
|
|
36
|
+
{
|
|
37
|
+
pRecordChunk.forEach(recordJsonMarshaller.write);
|
|
38
|
+
setImmediate(fNext);
|
|
39
|
+
},
|
|
40
|
+
(error) =>
|
|
41
|
+
{
|
|
42
|
+
recordJsonMarshaller.end();
|
|
43
|
+
fCallback(error);
|
|
44
|
+
});
|
|
45
|
+
};
|
|
@@ -736,10 +736,9 @@ suite
|
|
|
736
736
|
.end(
|
|
737
737
|
function (pError, pResponse)
|
|
738
738
|
{
|
|
739
|
-
console.log('FUCK'+pResponse.text)
|
|
740
739
|
var tmpResults = JSON.parse(pResponse.text);
|
|
741
|
-
Expect(tmpResults.length).to.equal(
|
|
742
|
-
Expect(tmpResults[0].Value).to.equal('FableTest #
|
|
740
|
+
Expect(tmpResults.length).to.equal(2);
|
|
741
|
+
Expect(tmpResults[0].Value).to.equal('FableTest #3');
|
|
743
742
|
fDone();
|
|
744
743
|
}
|
|
745
744
|
);
|
|
@@ -808,7 +807,6 @@ suite
|
|
|
808
807
|
function(fDone)
|
|
809
808
|
{
|
|
810
809
|
libSuperTest('http://localhost:9080/')
|
|
811
|
-
// Get page 2, 2 records per page.
|
|
812
810
|
.get('1.0/FableTests/FilteredTo/FBV~Type~EQ~Frog')
|
|
813
811
|
.end(
|
|
814
812
|
function (pError, pResponse)
|
|
@@ -820,13 +818,88 @@ suite
|
|
|
820
818
|
}
|
|
821
819
|
);
|
|
822
820
|
}
|
|
823
|
-
);
|
|
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
|
|
824
897
|
(
|
|
825
898
|
'reads: get a filtered paged set of records',
|
|
826
899
|
function(fDone)
|
|
827
900
|
{
|
|
828
901
|
libSuperTest('http://localhost:9080/')
|
|
829
|
-
//
|
|
902
|
+
// Skip one record, 2 records per page.
|
|
830
903
|
.get('1.0/FableTests/FilteredTo/FBV~Type~EQ~Dog/1/2')
|
|
831
904
|
.end(
|
|
832
905
|
function (pError, pResponse)
|
|
@@ -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
|
-
|
package/0002-Fix-indent.patch
DELETED
|
@@ -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;
|