meadow-endpoints 3.0.7 → 4.0.3
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/Dockerfile_LUXURYCode +1 -1
- package/README.md +48 -14
- package/debug/Animal.json +62 -0
- package/debug/Harness-Configuration.json +31 -0
- package/debug/Harness.js +7 -108
- package/debug/KillHarness.sh +10 -0
- package/dist/meadowendpoints.js +4402 -0
- package/dist/meadowendpoints.min.js +92 -0
- package/dist/meadowendpoints.min.js.map +1 -0
- package/gulpfile.js +83 -0
- package/package.json +27 -15
- package/source/Controller/Meadow-Endpoints-Controller-Base.js +161 -0
- package/source/Controller/components/Meadow-Endpoints-Controller-BehaviorInjection.js +125 -0
- package/source/Controller/components/Meadow-Endpoints-Controller-Error-StatusCodes.txt +189 -0
- package/source/Controller/components/Meadow-Endpoints-Controller-Error.js +118 -0
- package/source/Controller/components/Meadow-Endpoints-Controller-Log.js +103 -0
- package/source/Controller/utility/Meadow-Endpoints-Filter-Parser.js +225 -0
- package/source/Controller/utility/Meadow-Endpoints-Session-Marshaler.js +48 -0
- package/source/Controller/utility/Meadow-Endpoints-Stream-RecordArray.js +66 -0
- package/source/Meadow-Endpoints-Browser-Shim.js +14 -0
- package/source/Meadow-Endpoints.js +176 -565
- package/source/endpoints/count/Meadow-Endpoint-Count.js +49 -0
- package/source/endpoints/count/Meadow-Endpoint-CountBy.js +40 -0
- package/source/endpoints/create/Meadow-Endpoint-BulkCreate.js +53 -0
- package/source/endpoints/create/Meadow-Endpoint-Create.js +58 -0
- package/source/endpoints/create/Meadow-Operation-Create.js +83 -0
- package/source/endpoints/delete/Meadow-Endpoint-Delete.js +93 -0
- package/source/endpoints/delete/Meadow-Endpoint-Undelete.js +108 -0
- package/source/endpoints/read/Meadow-Endpoint-Read.js +72 -0
- package/source/endpoints/read/Meadow-Endpoint-ReadDistinctList.js +92 -0
- package/source/endpoints/read/Meadow-Endpoint-ReadLiteList.js +85 -0
- package/source/endpoints/read/Meadow-Endpoint-ReadMax.js +55 -0
- package/source/endpoints/read/Meadow-Endpoint-ReadSelectList.js +89 -0
- package/source/endpoints/read/Meadow-Endpoint-Reads.js +75 -0
- package/source/endpoints/read/Meadow-Endpoint-ReadsBy.js +100 -0
- package/source/{crud → endpoints/read}/Meadow-Marshal-DistinctList.js +4 -13
- package/source/{crud → endpoints/read}/Meadow-Marshal-LiteList.js +5 -14
- package/source/endpoints/schema/Meadow-Endpoint-New.js +36 -0
- package/source/endpoints/schema/Meadow-Endpoint-Schema.js +36 -0
- package/source/endpoints/schema/Meadow-Endpoint-Validate.js +41 -0
- package/source/endpoints/update/Meadow-Endpoint-BulkUpdate.js +50 -0
- package/source/endpoints/update/Meadow-Endpoint-Update.js +58 -0
- package/source/endpoints/update/Meadow-Operation-Update.js +115 -0
- package/source/endpoints/upsert/Meadow-Endpoint-BulkUpsert.js +53 -0
- package/source/endpoints/upsert/Meadow-Endpoint-Upsert.js +58 -0
- package/source/endpoints/upsert/Meadow-Operation-Upsert.js +132 -0
- package/test/MeadowEndpoints_basic_tests.js +50 -2408
- package/test_support/bookstore-api-endpoint-exercises.paw +0 -0
- package/test_support/bookstore-configuration.json +28 -0
- package/test_support/bookstore-import-books-run.js +1 -0
- package/test_support/bookstore-import-books.js +215 -0
- package/test_support/bookstore-serve-meadow-endpoint-apis-IPC.js +138 -0
- package/test_support/bookstore-serve-meadow-endpoint-apis-run.js +6 -0
- package/test_support/bookstore-serve-meadow-endpoint-apis.js +129 -0
- package/test_support/data/books.csv +10001 -0
- package/test_support/model/ddl/BookStore.ddl +66 -0
- package/test_support/model/generated_diagram/README.md +1 -0
- package/test_support/model/generated_diagram/Stricture_Output.dot +13 -0
- package/test_support/model/generated_diagram/Stricture_Output.png +0 -0
- package/test_support/model/generated_documentation/Dictionary.md +18 -0
- package/test_support/model/generated_documentation/Model-Author.md +20 -0
- package/test_support/model/generated_documentation/Model-Book.md +26 -0
- package/test_support/model/generated_documentation/Model-BookAuthorJoin.md +14 -0
- package/test_support/model/generated_documentation/Model-BookPrice.md +25 -0
- package/test_support/model/generated_documentation/Model-Review.md +22 -0
- package/test_support/model/generated_documentation/ModelChangeTracking.md +17 -0
- package/test_support/model/generated_documentation/README.md +1 -0
- package/test_support/model/manual_scripts/DropTables.sql +5 -0
- package/test_support/model/manual_scripts/README.md +2 -0
- package/test_support/model/sql_create/BookStore-CreateDatabase.mysql.sql +116 -0
- package/test_support/model/sql_create/README.md +1 -0
- package/test_support/test_old/Tests.js +3243 -0
- package/test_support/test_old/untitled.js +88 -0
- package/source/Meadow-Authenticator.js +0 -31
- package/source/Meadow-Authorizers.js +0 -214
- package/source/Meadow-BehaviorModifications.js +0 -170
- package/source/Meadow-CommonServices.js +0 -206
- package/source/Meadow-MarshallSessionData.js +0 -64
- package/source/Restify-RouteParser.js +0 -114
- package/source/authorizers/Meadow-Authorizer-Allow.js +0 -17
- package/source/authorizers/Meadow-Authorizer-Deny.js +0 -17
- package/source/authorizers/Meadow-Authorizer-Mine.js +0 -47
- package/source/authorizers/Meadow-Authorizer-MyCustomer.js +0 -48
- package/source/crud/Meadow-Endpoint-BulkCreate.js +0 -67
- package/source/crud/Meadow-Endpoint-BulkUpdate.js +0 -74
- package/source/crud/Meadow-Endpoint-BulkUpsert.js +0 -76
- package/source/crud/Meadow-Endpoint-Count.js +0 -93
- package/source/crud/Meadow-Endpoint-CountBy.js +0 -101
- package/source/crud/Meadow-Endpoint-Create.js +0 -77
- package/source/crud/Meadow-Endpoint-Delete.js +0 -139
- package/source/crud/Meadow-Endpoint-Read.js +0 -109
- package/source/crud/Meadow-Endpoint-ReadDistinctList.js +0 -146
- package/source/crud/Meadow-Endpoint-ReadLiteList.js +0 -139
- package/source/crud/Meadow-Endpoint-ReadMax.js +0 -86
- package/source/crud/Meadow-Endpoint-ReadSelectList.js +0 -145
- package/source/crud/Meadow-Endpoint-Reads.js +0 -129
- package/source/crud/Meadow-Endpoint-ReadsBy.js +0 -155
- package/source/crud/Meadow-Endpoint-Undelete.js +0 -161
- package/source/crud/Meadow-Endpoint-Update.js +0 -80
- package/source/crud/Meadow-Endpoint-Upsert.js +0 -78
- package/source/crud/Meadow-Operation-Create.js +0 -105
- package/source/crud/Meadow-Operation-Update.js +0 -145
- package/source/crud/Meadow-Operation-Upsert.js +0 -106
- package/source/crud/Meadow-StreamRecordArray.js +0 -45
- package/source/schema/Meadow-Endpoint-New.js +0 -37
- package/source/schema/Meadow-Endpoint-Schema.js +0 -37
- package/source/schema/Meadow-Endpoint-Validate.js +0 -43
- package/test/Animal.json +0 -140
- package/test/MeadowEndpoints_disabledAuth_tests.js +0 -1325
- package/test/MeadowEndpoints_trustedSession_tests.js +0 -1731
- package/test/load/artillery-low.yml +0 -10
- package/test/load/cloud9setup.sh +0 -25
- package/test/load/package.json +0 -19
- package/test/load/test-schema-initializedatabase.sql +0 -29
- package/test/load/test-schema.json +0 -119
- package/test/load/test-server.js +0 -157
- package/test/scripts/InitializeDatabase-C9.sql +0 -7
- /package/{test/schemas → test_support/model}/json_schema/BookStore-Extended.json +0 -0
- /package/{test/schemas → test_support/model}/json_schema/BookStore-PICT.json +0 -0
- /package/{test/schemas → test_support/model}/json_schema/BookStore.json +0 -0
- /package/{test/schemas → test_support/model}/json_schema/README.md +0 -0
- /package/{test/schemas → test_support/model}/meadow_schema/BookStore-MeadowSchema-Author.json +0 -0
- /package/{test/schemas → test_support/model}/meadow_schema/BookStore-MeadowSchema-Book.json +0 -0
- /package/{test/schemas → test_support/model}/meadow_schema/BookStore-MeadowSchema-BookAuthorJoin.json +0 -0
- /package/{test/schemas → test_support/model}/meadow_schema/BookStore-MeadowSchema-BookPrice.json +0 -0
- /package/{test/schemas → test_support/model}/meadow_schema/BookStore-MeadowSchema-Review.json +0 -0
- /package/{test/schemas → test_support/model}/meadow_schema/README.md +0 -0
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Meadow Endpoint - Count a Record
|
|
3
|
+
*/
|
|
4
|
+
const doAPIEndpointCount = function(pRequest, pResponse, fNext)
|
|
5
|
+
{
|
|
6
|
+
let tmpRequestState = this.initializeRequestState(pRequest, 'Count');
|
|
7
|
+
let fBehaviorInjector = (pBehaviorHash) => { return (fStageComplete) => { this.BehaviorInjection.runBehavior(pBehaviorHash, this, pRequest, tmpRequestState, fStageComplete); }; };
|
|
8
|
+
|
|
9
|
+
this.waterfall(
|
|
10
|
+
[
|
|
11
|
+
(fStageComplete) =>
|
|
12
|
+
{
|
|
13
|
+
tmpRequestState.Query = this.DAL.query;
|
|
14
|
+
if (typeof(pRequest.params.Filter) === 'string')
|
|
15
|
+
{
|
|
16
|
+
// If a filter has been passed in, parse it and add the values to the query.
|
|
17
|
+
this.parseFilter(pRequest.params.Filter, tmpRequestState.Query);
|
|
18
|
+
}
|
|
19
|
+
else if (pRequest.params.Filter)
|
|
20
|
+
{
|
|
21
|
+
tmpRequestState.Query.setFilter(pRequest.params.Filter);
|
|
22
|
+
}
|
|
23
|
+
return fStageComplete();
|
|
24
|
+
},
|
|
25
|
+
fBehaviorInjector(`Count-QueryConfiguration`),
|
|
26
|
+
(fStageComplete) =>
|
|
27
|
+
{
|
|
28
|
+
this.DAL.doCount(tmpRequestState.Query,
|
|
29
|
+
(pError, pQuery, pCount) =>
|
|
30
|
+
{
|
|
31
|
+
tmpRequestState.Result = {Count:pCount};
|
|
32
|
+
return fStageComplete(pError);
|
|
33
|
+
});
|
|
34
|
+
},
|
|
35
|
+
(fStageComplete) =>
|
|
36
|
+
{
|
|
37
|
+
pResponse.send(tmpRequestState.Result);
|
|
38
|
+
this.log.requestCompletedSuccessfully(pRequest, tmpRequestState, `Delivered recordset count of ${tmpRequestState.Result.Count} for ${this.DAL.scope}.`);
|
|
39
|
+
return fStageComplete();
|
|
40
|
+
}
|
|
41
|
+
],
|
|
42
|
+
(pError) =>
|
|
43
|
+
{
|
|
44
|
+
return this.ErrorHandler.handleErrorIfSet(pRequest, tmpRequestState, pResponse, pError, fNext);
|
|
45
|
+
}
|
|
46
|
+
);
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
module.exports = doAPIEndpointCount;
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Meadow Endpoint - Count a Record filtered by a single value
|
|
3
|
+
*/
|
|
4
|
+
const doAPIEndpointCountBy = function(pRequest, pResponse, fNext)
|
|
5
|
+
{
|
|
6
|
+
let tmpRequestState = this.initializeRequestState(pRequest, 'CountBy');
|
|
7
|
+
let fBehaviorInjector = (pBehaviorHash) => { return (fStageComplete) => { this.BehaviorInjection.runBehavior(pBehaviorHash, this, pRequest, tmpRequestState, fStageComplete); }; };
|
|
8
|
+
|
|
9
|
+
this.waterfall(
|
|
10
|
+
[
|
|
11
|
+
(fStageComplete) =>
|
|
12
|
+
{
|
|
13
|
+
tmpRequestState.Query = this.DAL.query;
|
|
14
|
+
tmpRequestState.Query.addFilter(pRequest.params.ByField, pRequest.params.ByValue, '=', 'AND', 'RequestByField');
|
|
15
|
+
return fStageComplete();
|
|
16
|
+
},
|
|
17
|
+
fBehaviorInjector(`CountBy-QueryConfiguration`),
|
|
18
|
+
(fStageComplete) =>
|
|
19
|
+
{
|
|
20
|
+
this.DAL.doCount(tmpRequestState.Query,
|
|
21
|
+
(pError, pQuery, pCount) =>
|
|
22
|
+
{
|
|
23
|
+
tmpRequestState.Result = {Count:pCount};
|
|
24
|
+
return fStageComplete(pError);
|
|
25
|
+
});
|
|
26
|
+
},
|
|
27
|
+
(fStageComplete) =>
|
|
28
|
+
{
|
|
29
|
+
this.log.requestCompletedSuccessfully(pRequest, tmpRequestState, 'Delivered recordset count of '+tmpRequestState.Result.Count+'.');
|
|
30
|
+
pResponse.send(tmpRequestState.Result);
|
|
31
|
+
return fStageComplete();
|
|
32
|
+
}
|
|
33
|
+
],
|
|
34
|
+
(pError) =>
|
|
35
|
+
{
|
|
36
|
+
return this.ErrorHandler.handleErrorIfSet(pRequest, tmpRequestState, pResponse, pError, fNext);
|
|
37
|
+
});
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
module.exports = doAPIEndpointCountBy;
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Meadow Endpoint - Create a set of Record in Bulk
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
const doCreate = require('./Meadow-Operation-Create.js');
|
|
6
|
+
|
|
7
|
+
const doAPIEndpointBulkCreate = function(pRequest, pResponse, fNext)
|
|
8
|
+
{
|
|
9
|
+
let tmpRequestState = this.initializeRequestState(pRequest, 'CreateBulk');
|
|
10
|
+
let fBehaviorInjector = (pBehaviorHash) => { return (fStageComplete) => { this.BehaviorInjection.runBehavior(pBehaviorHash, this, pRequest, tmpRequestState, fStageComplete); }; };
|
|
11
|
+
|
|
12
|
+
tmpRequestState.CreatedRecords = [];
|
|
13
|
+
|
|
14
|
+
this.waterfall(
|
|
15
|
+
[
|
|
16
|
+
(fStageComplete) =>
|
|
17
|
+
{
|
|
18
|
+
if (!Array.isArray(pRequest.body))
|
|
19
|
+
{
|
|
20
|
+
return fStageComplete(this.ErrorHandler.getError('Bulk record create failure - a valid array of records to create is required.', 500));
|
|
21
|
+
}
|
|
22
|
+
pRequest.RecordsToBulkCreate = pRequest.body;
|
|
23
|
+
|
|
24
|
+
return fStageComplete();
|
|
25
|
+
},
|
|
26
|
+
fBehaviorInjector(`CreateBulk-PreOperation`),
|
|
27
|
+
(fStageComplete) =>
|
|
28
|
+
{
|
|
29
|
+
// TODO: Research parallelism opportunities from custom routes
|
|
30
|
+
this.eachLimit(pRequest.RecordsToBulkCreate, 1,
|
|
31
|
+
(pRecord, fCallback) =>
|
|
32
|
+
{
|
|
33
|
+
doCreate.call(this, pRecord, pRequest, tmpRequestState, pResponse, fCallback);
|
|
34
|
+
}, fStageComplete);
|
|
35
|
+
},
|
|
36
|
+
fBehaviorInjector(`CreateBulk-PostOperation`),
|
|
37
|
+
(fStageComplete) =>
|
|
38
|
+
{
|
|
39
|
+
return this.doStreamRecordArray(pResponse, tmpRequestState.CreatedRecords, fStageComplete);
|
|
40
|
+
},
|
|
41
|
+
(fStageComplete) =>
|
|
42
|
+
{
|
|
43
|
+
this.log.requestCompletedSuccessfully(pRequest, tmpRequestState, `Bulk created ${tmpRequestState.CreatedRecords.length} records`);
|
|
44
|
+
return fStageComplete();
|
|
45
|
+
}
|
|
46
|
+
],
|
|
47
|
+
(pError) =>
|
|
48
|
+
{
|
|
49
|
+
return this.ErrorHandler.handleErrorIfSet(pRequest, tmpRequestState, pResponse, pError, fNext);
|
|
50
|
+
});
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
module.exports = doAPIEndpointBulkCreate;
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Meadow Endpoint - Create a Record
|
|
3
|
+
*/
|
|
4
|
+
const doCreate = require('./Meadow-Operation-Create.js');
|
|
5
|
+
|
|
6
|
+
const doAPIEndpointCreate = function(pRequest, pResponse, fNext)
|
|
7
|
+
{
|
|
8
|
+
let tmpRequestState = this.initializeRequestState(pRequest, 'Create');
|
|
9
|
+
let fBehaviorInjector = (pBehaviorHash) => { return (fStageComplete) => { this.BehaviorInjection.runBehavior(pBehaviorHash, this, pRequest, tmpRequestState, fStageComplete); }; };
|
|
10
|
+
|
|
11
|
+
this.waterfall(
|
|
12
|
+
[
|
|
13
|
+
(fStageComplete) =>
|
|
14
|
+
{
|
|
15
|
+
if (typeof(pRequest.body) !== 'object')
|
|
16
|
+
{
|
|
17
|
+
return fStageComplete(this.ErrorHandler.getError('Record create failure - a valid record is required.', 500));
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
return fStageComplete();
|
|
21
|
+
},
|
|
22
|
+
(fStageComplete) =>
|
|
23
|
+
{
|
|
24
|
+
doCreate.call(this, pRequest.body, pRequest, tmpRequestState, pResponse, fStageComplete);
|
|
25
|
+
},
|
|
26
|
+
(fStageComplete) =>
|
|
27
|
+
{
|
|
28
|
+
if (tmpRequestState.RecordCreateError)
|
|
29
|
+
{
|
|
30
|
+
return fStageComplete(tmpRequestState.RecordCreateErrorObject);
|
|
31
|
+
}
|
|
32
|
+
if (tmpRequestState.CreatedRecords.length < 1)
|
|
33
|
+
{
|
|
34
|
+
return fStageComplete(this.ErrorHandler.getError('Unknown record create failure - no created records returned.', 500));
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
tmpRequestState.Record = tmpRequestState.CreatedRecords[0];
|
|
38
|
+
|
|
39
|
+
return fStageComplete();
|
|
40
|
+
},
|
|
41
|
+
(fStageComplete) =>
|
|
42
|
+
{
|
|
43
|
+
pResponse.send(tmpRequestState.Record);
|
|
44
|
+
return fStageComplete();
|
|
45
|
+
},
|
|
46
|
+
(fStageComplete) =>
|
|
47
|
+
{
|
|
48
|
+
this.log.requestCompletedSuccessfully(pRequest, tmpRequestState, `Created a ${this.DAL.scope} record ID ${tmpRequestState.Record[this.DAL.defaultIdentifier]}`);
|
|
49
|
+
return fStageComplete();
|
|
50
|
+
}
|
|
51
|
+
],
|
|
52
|
+
(pError) =>
|
|
53
|
+
{
|
|
54
|
+
return this.ErrorHandler.handleErrorIfSet(pRequest, tmpRequestState, pResponse, pError, fNext);
|
|
55
|
+
});
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
module.exports = doAPIEndpointCreate;
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Meadow Operation - Create a record function
|
|
3
|
+
*/
|
|
4
|
+
const doCreate = function(pRecord, pRequest, pRequestState, pResponse, fCallback)
|
|
5
|
+
{
|
|
6
|
+
// This is a virtual operation
|
|
7
|
+
let tmpRequestState = this.cloneAsyncSafeRequestState(pRequestState, 'doCreate');
|
|
8
|
+
let fBehaviorInjector = (pBehaviorHash) => { return (fStageComplete) => { this.BehaviorInjection.runBehavior(pBehaviorHash, this, pRequest, tmpRequestState, fStageComplete); }; };
|
|
9
|
+
|
|
10
|
+
if (!Array.isArray(tmpRequestState.ParentRequestState.CreatedRecords))
|
|
11
|
+
{
|
|
12
|
+
tmpRequestState.ParentRequestState.CreatedRecords = [];
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
this.waterfall(
|
|
16
|
+
[
|
|
17
|
+
(fStageComplete) =>
|
|
18
|
+
{
|
|
19
|
+
tmpRequestState.RecordToCreate = pRecord;
|
|
20
|
+
|
|
21
|
+
//Make sure record gets created with a customerID
|
|
22
|
+
if (!tmpRequestState.RecordToCreate.hasOwnProperty('IDCustomer') && this.DAL.jsonSchema.properties.hasOwnProperty('IDCustomer'))
|
|
23
|
+
{
|
|
24
|
+
tmpRequestState.RecordToCreate.IDCustomer = tmpRequestState.SessionData.CustomerID || 0;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
return fStageComplete();
|
|
28
|
+
},
|
|
29
|
+
(fStageComplete) => { this.BehaviorInjection.runBehavior(`Create-PreOperation`, this, pRequest, tmpRequestState, fStageComplete); },
|
|
30
|
+
(fStageComplete) =>
|
|
31
|
+
{
|
|
32
|
+
// Prepare create query
|
|
33
|
+
tmpRequestState.Query = this.DAL.query;
|
|
34
|
+
tmpRequestState.Query.setIDUser(tmpRequestState.SessionData.UserID);
|
|
35
|
+
tmpRequestState.Query.addRecord(tmpRequestState.RecordToCreate);
|
|
36
|
+
return fStageComplete();
|
|
37
|
+
},
|
|
38
|
+
(fStageComplete) => { this.BehaviorInjection.runBehavior(`Create-QueryConfiguration`, this, pRequest, tmpRequestState, fStageComplete); },
|
|
39
|
+
(fStageComplete) =>
|
|
40
|
+
{
|
|
41
|
+
// Do the actual create operation with the DAL
|
|
42
|
+
this.DAL.doCreate(tmpRequestState.Query,
|
|
43
|
+
(pError, pQuery, pReadQuery, pNewRecord) =>
|
|
44
|
+
{
|
|
45
|
+
if (pError)
|
|
46
|
+
{
|
|
47
|
+
return fStageComplete(pError);
|
|
48
|
+
}
|
|
49
|
+
if (!pNewRecord)
|
|
50
|
+
{
|
|
51
|
+
return fStageComplete(this.ErrorHandler.getError(`Error in DAL Create: No record returned from persistence engine.`, 500));
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
tmpRequestState.Record = pNewRecord;
|
|
55
|
+
|
|
56
|
+
return fStageComplete();
|
|
57
|
+
});
|
|
58
|
+
},
|
|
59
|
+
(fStageComplete) => { return this.BehaviorInjection.runBehavior(`Create-PostOperation`, this, pRequest, tmpRequestState, fStageComplete); },
|
|
60
|
+
(fStageComplete) =>
|
|
61
|
+
{
|
|
62
|
+
tmpRequestState.ParentRequestState.CreatedRecords.push(tmpRequestState.Record);
|
|
63
|
+
this.log.requestCompletedSuccessfully(pRequest, tmpRequestState, `Created a record with ${this.DAL.defaultIdentifier} = ${tmpRequestState.Record[this.DAL.defaultIdentifier]}`);
|
|
64
|
+
return fStageComplete();
|
|
65
|
+
}
|
|
66
|
+
],
|
|
67
|
+
(pError) =>
|
|
68
|
+
{
|
|
69
|
+
if (pError)
|
|
70
|
+
{
|
|
71
|
+
tmpRequestState.RecordToCreate.Error = pError;
|
|
72
|
+
|
|
73
|
+
tmpRequestState.ParentRequestState.RecordCreateError = true;
|
|
74
|
+
tmpRequestState.ParentRequestState.RecordCreateErrorObject = pError;
|
|
75
|
+
|
|
76
|
+
tmpRequestState.ParentRequestState.CreatedRecords.push(tmpRequestState.RecordToCreate);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
return fCallback();
|
|
80
|
+
});
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
module.exports = doCreate;
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Meadow Endpoint - Delete a Record
|
|
3
|
+
*/
|
|
4
|
+
const doAPIEndpointDelete = function(pRequest, pResponse, fNext)
|
|
5
|
+
{
|
|
6
|
+
let tmpRequestState = this.initializeRequestState(pRequest, 'Delete');
|
|
7
|
+
let fBehaviorInjector = (pBehaviorHash) => { return (fStageComplete) => { this.BehaviorInjection.runBehavior(pBehaviorHash, this, pRequest, tmpRequestState, fStageComplete); }; };
|
|
8
|
+
|
|
9
|
+
tmpRequestState.IDRecord = 0;
|
|
10
|
+
tmpRequestState.RecordCount = { Count:0 };
|
|
11
|
+
|
|
12
|
+
this.waterfall(
|
|
13
|
+
[
|
|
14
|
+
(fStageComplete) =>
|
|
15
|
+
{
|
|
16
|
+
if (typeof(pRequest.params.IDRecord) === 'string')
|
|
17
|
+
{
|
|
18
|
+
tmpRequestState.IDRecord = pRequest.params.IDRecord;
|
|
19
|
+
}
|
|
20
|
+
else if (typeof(pRequest.body[this.DAL.defaultIdentifier]) === 'number')
|
|
21
|
+
{
|
|
22
|
+
tmpRequestState.IDRecord = pRequest.body[this.DAL.defaultIdentifier];
|
|
23
|
+
}
|
|
24
|
+
else if (typeof(pRequest.body[this.DAL.defaultIdentifier]) === 'string')
|
|
25
|
+
{
|
|
26
|
+
tmpRequestState.IDRecord = pRequest.body[this.DAL.defaultIdentifier];
|
|
27
|
+
}
|
|
28
|
+
// Although the Meadow delete behavior does allow multiple deletes, we require an identifier.
|
|
29
|
+
// If a developer wants bulk delete, it will require a custom endpoint.
|
|
30
|
+
if (tmpRequestState.IDRecord < 1)
|
|
31
|
+
{
|
|
32
|
+
return fStageComplete(this.ErrorHandler.getError('Record delete failure - a valid record ID is required in the passed-in record.', 500));
|
|
33
|
+
}
|
|
34
|
+
return fStageComplete();
|
|
35
|
+
},
|
|
36
|
+
(fStageComplete) =>
|
|
37
|
+
{
|
|
38
|
+
tmpRequestState.Query = this.DAL.query;
|
|
39
|
+
tmpRequestState.Query.addFilter(this.DAL.defaultIdentifier, tmpRequestState.IDRecord);
|
|
40
|
+
tmpRequestState.Query.setIDUser(tmpRequestState.SessionData.UserID);
|
|
41
|
+
return fStageComplete();
|
|
42
|
+
},
|
|
43
|
+
(fStageComplete) =>
|
|
44
|
+
{
|
|
45
|
+
return this.BehaviorInjection.runBehavior(`Delete-QueryConfiguration`, this, pRequest, tmpRequestState, fStageComplete);
|
|
46
|
+
},
|
|
47
|
+
(fStageComplete) =>
|
|
48
|
+
{
|
|
49
|
+
// Load the record so we can do security checks on it
|
|
50
|
+
this.DAL.doRead(tmpRequestState.Query,
|
|
51
|
+
(pError, pQuery, pRecord) =>
|
|
52
|
+
{
|
|
53
|
+
if (!pRecord)
|
|
54
|
+
{
|
|
55
|
+
return fStageComplete(this.ErrorHandler.getError('Record not found.', 404));
|
|
56
|
+
}
|
|
57
|
+
tmpRequestState.Record = pRecord;
|
|
58
|
+
return fStageComplete();
|
|
59
|
+
});
|
|
60
|
+
},
|
|
61
|
+
(fStageComplete) =>
|
|
62
|
+
{
|
|
63
|
+
return this.BehaviorInjection.runBehavior(`Delete-PreOperation`, this, pRequest, tmpRequestState, fStageComplete);
|
|
64
|
+
},
|
|
65
|
+
(fStageComplete) =>
|
|
66
|
+
{
|
|
67
|
+
// Do the delete
|
|
68
|
+
this.DAL.doDelete(tmpRequestState.Query,
|
|
69
|
+
(pError, pQuery, pCount) =>
|
|
70
|
+
{
|
|
71
|
+
// MySQL returns the number of rows deleted
|
|
72
|
+
tmpRequestState.RecordCount.Count = pCount;
|
|
73
|
+
return fStageComplete(pError);
|
|
74
|
+
});
|
|
75
|
+
},
|
|
76
|
+
(fStageComplete) =>
|
|
77
|
+
{
|
|
78
|
+
return this.BehaviorInjection.runBehavior(`Delete-PostOperation`, this, pRequest, tmpRequestState, fStageComplete);
|
|
79
|
+
},
|
|
80
|
+
(fStageComplete) =>
|
|
81
|
+
{
|
|
82
|
+
pResponse.send(tmpRequestState.RecordCount);
|
|
83
|
+
this.log.requestCompletedSuccessfully(pRequest, tmpRequestState, `Deleted ${tmpRequestState.RecordCount.Count} ${this.DAL.scope} records with ID ${tmpRequestState.IDRecord}`);
|
|
84
|
+
return fStageComplete();
|
|
85
|
+
}
|
|
86
|
+
], (pError) =>
|
|
87
|
+
{
|
|
88
|
+
return this.ErrorHandler.handleErrorIfSet(pRequest, tmpRequestState, pResponse, pError, fNext);
|
|
89
|
+
}
|
|
90
|
+
);
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
module.exports = doAPIEndpointDelete;
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Meadow Endpoint - Undelete a Record
|
|
3
|
+
*/
|
|
4
|
+
const doAPIEndpointUndelete = function(pRequest, pResponse, fNext)
|
|
5
|
+
{
|
|
6
|
+
let tmpRequestState = this.initializeRequestState(pRequest, 'Undelete');
|
|
7
|
+
let fBehaviorInjector = (pBehaviorHash) => { return (fStageComplete) => { this.BehaviorInjection.runBehavior(pBehaviorHash, this, pRequest, tmpRequestState, fStageComplete); }; };
|
|
8
|
+
|
|
9
|
+
var tmpIDRecord = 0;
|
|
10
|
+
if (typeof(pRequest.params.IDRecord) === 'string')
|
|
11
|
+
{
|
|
12
|
+
tmpIDRecord = pRequest.params.IDRecord;
|
|
13
|
+
}
|
|
14
|
+
else if (typeof(pRequest.body[this.DAL.defaultIdentifier]) === 'number')
|
|
15
|
+
{
|
|
16
|
+
tmpIDRecord = pRequest.body[this.DAL.defaultIdentifier];
|
|
17
|
+
}
|
|
18
|
+
else if (typeof(pRequest.body[this.DAL.defaultIdentifier]) === 'string')
|
|
19
|
+
{
|
|
20
|
+
tmpIDRecord = pRequest.body[this.DAL.defaultIdentifier];
|
|
21
|
+
}
|
|
22
|
+
// Although the undelete request does allow multiple undeletes, we require an identifier.
|
|
23
|
+
// TODO: Decide if we want to keep this pattern similar to Delete, or, if we want to change it to allow bulk undeletes.
|
|
24
|
+
if (tmpIDRecord < 1)
|
|
25
|
+
{
|
|
26
|
+
return fStageComplete(this.ErrorHandler.getError('Record undelete failure - a valid record ID is required.', 500));
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
tmpRequestState.RecordCount = {Count:0};
|
|
30
|
+
|
|
31
|
+
this.waterfall(
|
|
32
|
+
[
|
|
33
|
+
(fStageComplete) =>
|
|
34
|
+
{
|
|
35
|
+
// Validate that the schema has a deleted bit
|
|
36
|
+
var tmpSchema = this.DAL.schema;
|
|
37
|
+
var tmpHasDeletedBit = false;
|
|
38
|
+
for (let i = 0; i < tmpSchema.length; i++)
|
|
39
|
+
{
|
|
40
|
+
if (tmpSchema[i].Type == 'Deleted')
|
|
41
|
+
{
|
|
42
|
+
tmpHasDeletedBit = true;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
if (!tmpHasDeletedBit)
|
|
47
|
+
{
|
|
48
|
+
return fStageComplete(this.ErrorHandler.getError('No undelete bit on record.', 500));
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
return fStageComplete();
|
|
52
|
+
},
|
|
53
|
+
(fStageComplete) =>
|
|
54
|
+
{
|
|
55
|
+
// Now see if the record, with this identifier, for this user, exists with the deleted bit set to 1
|
|
56
|
+
tmpRequestState.Query = this.DAL.query;
|
|
57
|
+
tmpRequestState.Query.addFilter(this.DAL.defaultIdentifier, tmpIDRecord);
|
|
58
|
+
tmpRequestState.Query.addFilter('Deleted', 1);
|
|
59
|
+
tmpRequestState.Query.setIDUser(tmpRequestState.SessionData.UserID);
|
|
60
|
+
return fStageComplete();
|
|
61
|
+
},
|
|
62
|
+
(fStageComplete) =>
|
|
63
|
+
{
|
|
64
|
+
// Load the record so we can do security checks on it
|
|
65
|
+
this.DAL.doRead(tmpRequestState.Query,
|
|
66
|
+
(pError, pQuery, pRecord) =>
|
|
67
|
+
{
|
|
68
|
+
if (!pRecord)
|
|
69
|
+
{
|
|
70
|
+
return fStageComplete(this.ErrorHandler.getError('Record not found.', 404));
|
|
71
|
+
}
|
|
72
|
+
tmpRequestState.Record = pRecord;
|
|
73
|
+
return fStageComplete();
|
|
74
|
+
});
|
|
75
|
+
},
|
|
76
|
+
(fStageComplete) =>
|
|
77
|
+
{
|
|
78
|
+
return this.BehaviorInjection.runBehavior(`Undelete-PreOperation`, this, pRequest, tmpRequestState, fStageComplete);
|
|
79
|
+
},
|
|
80
|
+
(fStageComplete) =>
|
|
81
|
+
{
|
|
82
|
+
// Do the undelete
|
|
83
|
+
this.DAL.doUndelete(tmpRequestState.Query,
|
|
84
|
+
(pError, pQuery, pCount) =>
|
|
85
|
+
{
|
|
86
|
+
// MySQL returns the number of rows deleted
|
|
87
|
+
tmpRequestState.RecordCount = {Count:pCount};
|
|
88
|
+
return fStageComplete(pError);
|
|
89
|
+
});
|
|
90
|
+
},
|
|
91
|
+
(fStageComplete) =>
|
|
92
|
+
{
|
|
93
|
+
return this.BehaviorInjection.runBehavior(`Undelete-PostOperation`, this, pRequest, tmpRequestState, fStageComplete);
|
|
94
|
+
},
|
|
95
|
+
(fStageComplete) =>
|
|
96
|
+
{
|
|
97
|
+
pResponse.send(tmpRequestState.RecordCount);
|
|
98
|
+
this.log.requestCompletedSuccessfully(pRequest, tmpRequestState, 'Undeleted '+tmpRequestState.RecordCount.Count+' records with ID '+tmpIDRecord+'.');
|
|
99
|
+
return fStageComplete();
|
|
100
|
+
}
|
|
101
|
+
], (pError) =>
|
|
102
|
+
{
|
|
103
|
+
return this.ErrorHandler.handleErrorIfSet(pRequest, tmpRequestState, pResponse, pError, fNext);
|
|
104
|
+
}
|
|
105
|
+
);
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
module.exports = doAPIEndpointUndelete;
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Meadow Endpoint - Read a Record
|
|
3
|
+
*/
|
|
4
|
+
const doAPIEndpointRead = function(pRequest, pResponse, fNext)
|
|
5
|
+
{
|
|
6
|
+
let tmpRequestState = this.initializeRequestState(pRequest, 'Read');
|
|
7
|
+
let fBehaviorInjector = (pBehaviorHash) => { return (fStageComplete) => { this.BehaviorInjection.runBehavior(pBehaviorHash, this, pRequest, tmpRequestState, fStageComplete); }; };
|
|
8
|
+
|
|
9
|
+
this.waterfall(
|
|
10
|
+
[
|
|
11
|
+
(fStageComplete) =>
|
|
12
|
+
{
|
|
13
|
+
tmpRequestState.Query = this.DAL.query;
|
|
14
|
+
return fStageComplete();
|
|
15
|
+
},
|
|
16
|
+
fBehaviorInjector(`Read-PreOperation`),
|
|
17
|
+
(fStageComplete) =>
|
|
18
|
+
{
|
|
19
|
+
if (!pRequest.params.IDRecord && pRequest.params.GUIDRecord)
|
|
20
|
+
{
|
|
21
|
+
// We use a custom name for this (RequestDefaultIdentifier) in case there is a query with a dot in the default identifier.
|
|
22
|
+
tmpRequestState.RecordSearchCriteria = `${this.DAL.defaultGUIdentifier} = ${pRequest.params.GUIDRecord}`;
|
|
23
|
+
tmpRequestState.Query.addFilter(this.DAL.defaultGUIdentifier, pRequest.params.GUIDRecord, '=', 'AND', 'RequestDefaultIdentifier');
|
|
24
|
+
}
|
|
25
|
+
else if (pRequest.params.IDRecord)
|
|
26
|
+
{
|
|
27
|
+
// We use a custon name for this (RequestDefaultIdentifier) in case there is a query with a dot in the default identifier.
|
|
28
|
+
tmpRequestState.RecordSearchCriteria = `${this.DAL.defaultIdentifier} = ${pRequest.params.IDRecord}`;
|
|
29
|
+
tmpRequestState.Query.addFilter(this.DAL.defaultIdentifier, pRequest.params.IDRecord, '=', 'AND', 'RequestDefaultIdentifier');
|
|
30
|
+
}
|
|
31
|
+
else
|
|
32
|
+
{
|
|
33
|
+
return fStageComplete(this.ErrorHandler.getError('No ID Provided', 400));
|
|
34
|
+
}
|
|
35
|
+
return fStageComplete();
|
|
36
|
+
},
|
|
37
|
+
fBehaviorInjector(`Read-QueryConfiguration`),
|
|
38
|
+
(fStageComplete) =>
|
|
39
|
+
{
|
|
40
|
+
try
|
|
41
|
+
{
|
|
42
|
+
this.DAL.doRead(tmpRequestState.Query, (pError, pQuery, pRecord) =>
|
|
43
|
+
{
|
|
44
|
+
if (!pRecord)
|
|
45
|
+
{
|
|
46
|
+
return fStageComplete(this.ErrorHandler.getError('Record not Found', 404));
|
|
47
|
+
}
|
|
48
|
+
tmpRequestState.Record = pRecord;
|
|
49
|
+
return fStageComplete();
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
catch (pQueryError)
|
|
53
|
+
{
|
|
54
|
+
return fStageComplete(pQueryError);
|
|
55
|
+
}
|
|
56
|
+
},
|
|
57
|
+
fBehaviorInjector(`Read-PostOperation`),
|
|
58
|
+
(fStageComplete) =>
|
|
59
|
+
{
|
|
60
|
+
pResponse.send(tmpRequestState.Record);
|
|
61
|
+
this.log.requestCompletedSuccessfully(pRequest, tmpRequestState, `Read Record Where ${tmpRequestState.RecordSearchCriteria}`);
|
|
62
|
+
return fStageComplete();
|
|
63
|
+
}
|
|
64
|
+
],
|
|
65
|
+
(pError) =>
|
|
66
|
+
{
|
|
67
|
+
return this.ErrorHandler.handleErrorIfSet(pRequest, tmpRequestState, pResponse, pError, fNext);
|
|
68
|
+
}
|
|
69
|
+
);
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
module.exports = doAPIEndpointRead;
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Meadow Endpoint - Read a list of Records with a specified set of columns, distinct by those columns.
|
|
3
|
+
*/
|
|
4
|
+
const marshalDistinctList = require('./Meadow-Marshal-DistinctList.js');
|
|
5
|
+
|
|
6
|
+
const doAPIEndpointReadDistinct = function(pRequest, pResponse, fNext)
|
|
7
|
+
{
|
|
8
|
+
let tmpRequestState = this.initializeRequestState(pRequest, 'ReadDistinct');
|
|
9
|
+
let fBehaviorInjector = (pBehaviorHash) => { return (fStageComplete) => { this.BehaviorInjection.runBehavior(pBehaviorHash, this, pRequest, tmpRequestState, fStageComplete); }; };
|
|
10
|
+
|
|
11
|
+
tmpRequestState.DistinctColumns;
|
|
12
|
+
|
|
13
|
+
this.waterfall(
|
|
14
|
+
[
|
|
15
|
+
(fStageComplete) =>
|
|
16
|
+
{
|
|
17
|
+
tmpRequestState.Query = this.DAL.query.setDistinct(true);
|
|
18
|
+
|
|
19
|
+
let tmpCap = false;
|
|
20
|
+
let tmpBegin = false;
|
|
21
|
+
if (typeof(pRequest.params.Begin) === 'string' ||
|
|
22
|
+
typeof(pRequest.params.Begin) === 'number')
|
|
23
|
+
{
|
|
24
|
+
tmpBegin = parseInt(pRequest.params.Begin, 10);
|
|
25
|
+
}
|
|
26
|
+
if (typeof(pRequest.params.Cap) === 'string' ||
|
|
27
|
+
typeof(pRequest.params.Cap) === 'number')
|
|
28
|
+
{
|
|
29
|
+
tmpCap = parseInt(pRequest.params.Cap, 10);
|
|
30
|
+
}
|
|
31
|
+
else
|
|
32
|
+
{
|
|
33
|
+
//maximum number of records to return by default on Read queries. Override via "MeadowDefaultMaxCap" fable setting.
|
|
34
|
+
tmpCap = (this.settings['MeadowDefaultMaxCap']) || 250;
|
|
35
|
+
}
|
|
36
|
+
tmpRequestState.Query.setCap(tmpCap).setBegin(tmpBegin);
|
|
37
|
+
if (typeof(pRequest.params.Filter) === 'string')
|
|
38
|
+
{
|
|
39
|
+
// If a filter has been passed in, parse it and add the values to the query.
|
|
40
|
+
this.parseFilter(pRequest.params.Filter, tmpRequestState.Query);
|
|
41
|
+
}
|
|
42
|
+
else if (pRequest.params.Filter)
|
|
43
|
+
{
|
|
44
|
+
tmpRequestState.Query.setFilter(pRequest.params.Filter);
|
|
45
|
+
}
|
|
46
|
+
if (typeof(pRequest.params.Columns) === 'string')
|
|
47
|
+
{
|
|
48
|
+
tmpRequestState.DistinctColumns = pRequest.params.Columns.split(',');
|
|
49
|
+
if (!tmpRequestState.DistinctColumns)
|
|
50
|
+
{
|
|
51
|
+
return fStageComplete({Code:400, Message:'Columns to distinct on must be provided.'});
|
|
52
|
+
}
|
|
53
|
+
tmpRequestState.Query.setDataElements(tmpRequestState.DistinctColumns);
|
|
54
|
+
}
|
|
55
|
+
return fStageComplete();
|
|
56
|
+
},
|
|
57
|
+
fBehaviorInjector(`Reads-QueryConfiguration`),
|
|
58
|
+
(fStageComplete) =>
|
|
59
|
+
{
|
|
60
|
+
this.DAL.doReads(tmpRequestState.Query, fStageComplete);
|
|
61
|
+
},
|
|
62
|
+
(pQuery, pRecords, fStageComplete) =>
|
|
63
|
+
{
|
|
64
|
+
if (pRecords.length < 1)
|
|
65
|
+
{
|
|
66
|
+
pRecords = [];
|
|
67
|
+
}
|
|
68
|
+
tmpRequestState.Records = pRecords;
|
|
69
|
+
return fStageComplete();
|
|
70
|
+
},
|
|
71
|
+
(fStageComplete) =>
|
|
72
|
+
{
|
|
73
|
+
tmpRequestState.ResultRecords = marshalDistinctList.call(this, tmpRequestState.Records, pRequest, tmpRequestState.DistinctColumns);
|
|
74
|
+
return fStageComplete();
|
|
75
|
+
},
|
|
76
|
+
(fStageComplete) =>
|
|
77
|
+
{
|
|
78
|
+
return this.doStreamRecordArray(pResponse, tmpRequestState.ResultRecords, fStageComplete);
|
|
79
|
+
},
|
|
80
|
+
(fStageComplete) =>
|
|
81
|
+
{
|
|
82
|
+
this.log.requestCompletedSuccessfully(pRequest, tmpRequestState, `Read a recordset distinct lite list with ${tmpRequestState.ResultRecords.length} results.`);
|
|
83
|
+
return fStageComplete();
|
|
84
|
+
}
|
|
85
|
+
],
|
|
86
|
+
(pError) =>
|
|
87
|
+
{
|
|
88
|
+
return this.ErrorHandler.handleErrorIfSet(pRequest, tmpRequestState, pResponse, pError, fNext);
|
|
89
|
+
});
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
module.exports = doAPIEndpointReadDistinct;
|