meadow-endpoints 4.0.16 → 4.0.17

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.
@@ -5918,10 +5918,22 @@ this.parseFilter(pRequest.params.Filter,tmpRequestState.Query);}else if(pRequest
5918
5918
  * Meadow Endpoint - Count a Record filtered by a single value
5919
5919
  */const doAPIEndpointCountBy=function(pRequest,pResponse,fNext){let tmpRequestState=this.initializeRequestState(pRequest,'CountBy');let fBehaviorInjector=pBehaviorHash=>{return fStageComplete=>{this.BehaviorInjection.runBehavior(pBehaviorHash,this,pRequest,tmpRequestState,fStageComplete);};};this.waterfall([fStageComplete=>{tmpRequestState.Query=this.DAL.query;tmpRequestState.Query.addFilter(pRequest.params.ByField,pRequest.params.ByValue,'=','AND','RequestByField');return fStageComplete();},fBehaviorInjector(`CountBy-QueryConfiguration`),fStageComplete=>{this.DAL.doCount(tmpRequestState.Query,(pError,pQuery,pCount)=>{tmpRequestState.Result={Count:pCount};return fStageComplete(pError);});},fStageComplete=>{this.log.requestCompletedSuccessfully(pRequest,tmpRequestState,'Delivered recordset count of '+tmpRequestState.Result.Count+'.');pResponse.send(tmpRequestState.Result);return fStageComplete();}],pError=>{return this.ErrorHandler.handleErrorIfSet(pRequest,tmpRequestState,pResponse,pError,fNext);});};module.exports=doAPIEndpointCountBy;},{}],201:[function(require,module,exports){/**
5920
5920
  * Meadow Endpoint - Create a set of Record in Bulk
5921
- */const doCreate=require('./Meadow-Operation-Create.js');const doAPIEndpointBulkCreate=function(pRequest,pResponse,fNext){let tmpRequestState=this.initializeRequestState(pRequest,'CreateBulk');let fBehaviorInjector=pBehaviorHash=>{return fStageComplete=>{this.BehaviorInjection.runBehavior(pBehaviorHash,this,pRequest,tmpRequestState,fStageComplete);};};tmpRequestState.CreatedRecords=[];this.waterfall([fStageComplete=>{if(!Array.isArray(pRequest.body)){return fStageComplete(this.ErrorHandler.getError('Bulk record create failure - a valid array of records to create is required.',500));}pRequest.RecordsToBulkCreate=pRequest.body;return fStageComplete();},fBehaviorInjector(`CreateBulk-PreOperation`),fStageComplete=>{// TODO: Research parallelism opportunities from custom routes
5921
+ */const doCreate=require('./Meadow-Operation-Create.js');const doAPIEndpointBulkCreate=function(pRequest,pResponse,fNext){let tmpRequestState=this.initializeRequestState(pRequest,'CreateBulk');let fBehaviorInjector=pBehaviorHash=>{return fStageComplete=>{this.BehaviorInjection.runBehavior(pBehaviorHash,this,pRequest,tmpRequestState,fStageComplete);};};tmpRequestState.CreatedRecords=[];this.waterfall([fStageComplete=>{if(!Array.isArray(pRequest.body)){return fStageComplete(this.ErrorHandler.getError('Bulk record create failure - a valid array of records to create is required.',500));}pRequest.RecordsToBulkCreate=pRequest.body;return fStageComplete();},// Endpoint-level pre-request hook for bulk creates. Mirror of
5922
+ // Create-PreRequest in the singular Create endpoint — fires
5923
+ // after body-array validation and before any per-record
5924
+ // operation. Use cases include bulk idempotency suppression /
5925
+ // dedup across the incoming batch.
5926
+ fBehaviorInjector(`CreateBulk-PreRequest`),fBehaviorInjector(`CreateBulk-PreOperation`),fStageComplete=>{// TODO: Research parallelism opportunities from custom routes
5922
5927
  this.eachLimit(pRequest.RecordsToBulkCreate,1,(pRecord,fCallback)=>{doCreate.call(this,pRecord,pRequest,tmpRequestState,pResponse,fCallback);},fStageComplete);},fBehaviorInjector(`CreateBulk-PostOperation`),fStageComplete=>{return this.doStreamRecordArray(pResponse,tmpRequestState.CreatedRecords,fStageComplete);},fStageComplete=>{this.log.requestCompletedSuccessfully(pRequest,tmpRequestState,`Bulk created ${tmpRequestState.CreatedRecords.length} records`);return fStageComplete();}],pError=>{return this.ErrorHandler.handleErrorIfSet(pRequest,tmpRequestState,pResponse,pError,fNext);});};module.exports=doAPIEndpointBulkCreate;},{"./Meadow-Operation-Create.js":203}],202:[function(require,module,exports){/**
5923
5928
  * Meadow Endpoint - Create a Record
5924
- */const doCreate=require('./Meadow-Operation-Create.js');const doAPIEndpointCreate=function(pRequest,pResponse,fNext){let tmpRequestState=this.initializeRequestState(pRequest,'Create');let fBehaviorInjector=pBehaviorHash=>{return fStageComplete=>{this.BehaviorInjection.runBehavior(pBehaviorHash,this,pRequest,tmpRequestState,fStageComplete);};};this.waterfall([fStageComplete=>{if(typeof pRequest.body!=='object'){return fStageComplete(this.ErrorHandler.getError('Record create failure - a valid record is required.',500));}return fStageComplete();},fStageComplete=>{doCreate.call(this,pRequest.body,pRequest,tmpRequestState,pResponse,fStageComplete);},fStageComplete=>{if(tmpRequestState.RecordCreateError){return fStageComplete(tmpRequestState.RecordCreateErrorObject);}if(tmpRequestState.CreatedRecords.length<1){return fStageComplete(this.ErrorHandler.getError('Unknown record create failure - no created records returned.',500));}tmpRequestState.Record=tmpRequestState.CreatedRecords[0];return fStageComplete();},fStageComplete=>{pResponse.send(tmpRequestState.Record);return fStageComplete();},fStageComplete=>{this.log.requestCompletedSuccessfully(pRequest,tmpRequestState,`Created a ${this.DAL.scope} record ID ${tmpRequestState.Record[this.DAL.defaultIdentifier]}`);return fStageComplete();}],pError=>{return this.ErrorHandler.handleErrorIfSet(pRequest,tmpRequestState,pResponse,pError,fNext);});};module.exports=doAPIEndpointCreate;},{"./Meadow-Operation-Create.js":203}],203:[function(require,module,exports){/**
5929
+ */const doCreate=require('./Meadow-Operation-Create.js');const doAPIEndpointCreate=function(pRequest,pResponse,fNext){let tmpRequestState=this.initializeRequestState(pRequest,'Create');let fBehaviorInjector=pBehaviorHash=>{return fStageComplete=>{this.BehaviorInjection.runBehavior(pBehaviorHash,this,pRequest,tmpRequestState,fStageComplete);};};this.waterfall([fStageComplete=>{if(typeof pRequest.body!=='object'){return fStageComplete(this.ErrorHandler.getError('Record create failure - a valid record is required.',500));}return fStageComplete();},// Endpoint-level pre-request hook. Runs after the body-type check
5930
+ // but before any operation work, mirroring ME 2.x's
5931
+ // Create-PreRequest stage. Use cases include idempotency
5932
+ // suppression (e.g. look up by primary GUID and short-circuit
5933
+ // if the row already exists). Handlers can abort the operation
5934
+ // by calling fStageComplete with a truthy error or by fully
5935
+ // writing pResponse and returning a sentinel.
5936
+ fBehaviorInjector(`Create-PreRequest`),fStageComplete=>{doCreate.call(this,pRequest.body,pRequest,tmpRequestState,pResponse,fStageComplete);},fStageComplete=>{if(tmpRequestState.RecordCreateError){return fStageComplete(tmpRequestState.RecordCreateErrorObject);}if(tmpRequestState.CreatedRecords.length<1){return fStageComplete(this.ErrorHandler.getError('Unknown record create failure - no created records returned.',500));}tmpRequestState.Record=tmpRequestState.CreatedRecords[0];return fStageComplete();},fStageComplete=>{pResponse.send(tmpRequestState.Record);return fStageComplete();},fStageComplete=>{this.log.requestCompletedSuccessfully(pRequest,tmpRequestState,`Created a ${this.DAL.scope} record ID ${tmpRequestState.Record[this.DAL.defaultIdentifier]}`);return fStageComplete();}],pError=>{return this.ErrorHandler.handleErrorIfSet(pRequest,tmpRequestState,pResponse,pError,fNext);});};module.exports=doAPIEndpointCreate;},{"./Meadow-Operation-Create.js":203}],203:[function(require,module,exports){/**
5925
5937
  * Meadow Operation - Create a record function
5926
5938
  */const doCreate=function(pRecord,pRequest,pRequestState,pResponse,fCallback){// This is a virtual operation
5927
5939
  let tmpRequestState=this.cloneAsyncSafeRequestState(pRequestState,'doCreate');let fBehaviorInjector=pBehaviorHash=>{return fStageComplete=>{this.BehaviorInjection.runBehavior(pBehaviorHash,this,pRequest,tmpRequestState,fStageComplete);};};if(!Array.isArray(tmpRequestState.ParentRequestState.CreatedRecords)){tmpRequestState.ParentRequestState.CreatedRecords=[];}this.waterfall([fStageComplete=>{tmpRequestState.RecordToCreate=pRecord;//Make sure record gets created with a customerID
@@ -5932,7 +5944,12 @@ this.DAL.doCreate(tmpRequestState.Query,(pError,pQuery,pReadQuery,pNewRecord)=>{
5932
5944
  */const doAPIEndpointDelete=function(pRequest,pResponse,fNext){let tmpRequestState=this.initializeRequestState(pRequest,'Delete');let fBehaviorInjector=pBehaviorHash=>{return fStageComplete=>{this.BehaviorInjection.runBehavior(pBehaviorHash,this,pRequest,tmpRequestState,fStageComplete);};};tmpRequestState.IDRecord=0;tmpRequestState.RecordCount={Count:0};this.waterfall([fStageComplete=>{if(typeof pRequest.params.IDRecord==='string'){tmpRequestState.IDRecord=pRequest.params.IDRecord;}else if(typeof pRequest.body[this.DAL.defaultIdentifier]==='number'){tmpRequestState.IDRecord=pRequest.body[this.DAL.defaultIdentifier];}else if(typeof pRequest.body[this.DAL.defaultIdentifier]==='string'){tmpRequestState.IDRecord=pRequest.body[this.DAL.defaultIdentifier];}// Although the Meadow delete behavior does allow multiple deletes, we require an identifier.
5933
5945
  // If a developer wants bulk delete, it will require a custom endpoint.
5934
5946
  if(tmpRequestState.IDRecord<1){return fStageComplete(this.ErrorHandler.getError('Record delete failure - a valid record ID is required in the passed-in record.',500));}return fStageComplete();},fStageComplete=>{tmpRequestState.Query=this.DAL.query;tmpRequestState.Query.addFilter(this.DAL.defaultIdentifier,tmpRequestState.IDRecord);tmpRequestState.Query.setIDUser(tmpRequestState.SessionData.UserID);return fStageComplete();},fStageComplete=>{return this.BehaviorInjection.runBehavior(`Delete-QueryConfiguration`,this,pRequest,tmpRequestState,fStageComplete);},fStageComplete=>{// Load the record so we can do security checks on it
5935
- this.DAL.doRead(tmpRequestState.Query,(pError,pQuery,pRecord)=>{if(!pRecord){return fStageComplete(this.ErrorHandler.getError('Record not found.',404));}tmpRequestState.Record=pRecord;return fStageComplete();});},fStageComplete=>{return this.BehaviorInjection.runBehavior(`Delete-PreOperation`,this,pRequest,tmpRequestState,fStageComplete);},fStageComplete=>{// Do the delete
5947
+ this.DAL.doRead(tmpRequestState.Query,(pError,pQuery,pRecord)=>{if(!pRecord){return fStageComplete(this.ErrorHandler.getError('Record not found.',404));}tmpRequestState.Record=pRecord;// Alias the loaded pre-delete row for symmetry
5948
+ // with Update (see Meadow-Operation-Update.js).
5949
+ // Post-op hooks that compare pre/post values can
5950
+ // reliably read OriginalRecord without having to
5951
+ // know which stage overwrote Record.
5952
+ tmpRequestState.OriginalRecord=pRecord;return fStageComplete();});},fStageComplete=>{return this.BehaviorInjection.runBehavior(`Delete-PreOperation`,this,pRequest,tmpRequestState,fStageComplete);},fStageComplete=>{// Do the delete
5936
5953
  this.DAL.doDelete(tmpRequestState.Query,(pError,pQuery,pCount)=>{// MySQL returns the number of rows deleted
5937
5954
  tmpRequestState.RecordCount.Count=pCount;return fStageComplete(pError);});},fStageComplete=>{return this.BehaviorInjection.runBehavior(`Delete-PostOperation`,this,pRequest,tmpRequestState,fStageComplete);},fStageComplete=>{pResponse.send(tmpRequestState.RecordCount);this.log.requestCompletedSuccessfully(pRequest,tmpRequestState,`Deleted ${tmpRequestState.RecordCount.Count} ${this.DAL.scope} records with ID ${tmpRequestState.IDRecord}`);return fStageComplete();}],pError=>{return this.ErrorHandler.handleErrorIfSet(pRequest,tmpRequestState,pResponse,pError,fNext);});};module.exports=doAPIEndpointDelete;},{}],205:[function(require,module,exports){/**
5938
5955
  * Meadow Endpoint - Undelete a Record
@@ -5941,7 +5958,11 @@ tmpRequestState.RecordCount.Count=pCount;return fStageComplete(pError);});},fSta
5941
5958
  if(tmpIDRecord<1){return fNext(this.ErrorHandler.getError('Record undelete failure - a valid record ID is required.',500));}tmpRequestState.RecordCount={Count:0};this.waterfall([fStageComplete=>{// Validate that the schema has a deleted bit
5942
5959
  var tmpSchema=this.DAL.schema;var tmpHasDeletedBit=false;for(let i=0;i<tmpSchema.length;i++){if(tmpSchema[i].Type=='Deleted'){tmpHasDeletedBit=true;}}if(!tmpHasDeletedBit){return fStageComplete(this.ErrorHandler.getError('No undelete bit on record.',500));}return fStageComplete();},fStageComplete=>{// Now see if the record, with this identifier, for this user, exists with the deleted bit set to 1
5943
5960
  tmpRequestState.Query=this.DAL.query;tmpRequestState.Query.addFilter(this.DAL.defaultIdentifier,tmpIDRecord);tmpRequestState.Query.addFilter('Deleted',1);tmpRequestState.Query.setIDUser(tmpRequestState.SessionData.UserID);return fStageComplete();},fStageComplete=>{// Load the record so we can do security checks on it
5944
- this.DAL.doRead(tmpRequestState.Query,(pError,pQuery,pRecord)=>{if(!pRecord){return fStageComplete(this.ErrorHandler.getError('Record not found.',404));}tmpRequestState.Record=pRecord;return fStageComplete();});},fStageComplete=>{return this.BehaviorInjection.runBehavior(`Undelete-PreOperation`,this,pRequest,tmpRequestState,fStageComplete);},fStageComplete=>{// Do the undelete
5961
+ this.DAL.doRead(tmpRequestState.Query,(pError,pQuery,pRecord)=>{if(!pRecord){return fStageComplete(this.ErrorHandler.getError('Record not found.',404));}tmpRequestState.Record=pRecord;// Alias the loaded pre-undelete row for symmetry
5962
+ // with Update / Delete (see their endpoints). Post-op
5963
+ // hooks that compare pre/post values can reliably
5964
+ // read OriginalRecord.
5965
+ tmpRequestState.OriginalRecord=pRecord;return fStageComplete();});},fStageComplete=>{return this.BehaviorInjection.runBehavior(`Undelete-PreOperation`,this,pRequest,tmpRequestState,fStageComplete);},fStageComplete=>{// Do the undelete
5945
5966
  this.DAL.doUndelete(tmpRequestState.Query,(pError,pQuery,pCount)=>{// MySQL returns the number of rows deleted
5946
5967
  tmpRequestState.RecordCount={Count:pCount};return fStageComplete(pError);});},fStageComplete=>{return this.BehaviorInjection.runBehavior(`Undelete-PostOperation`,this,pRequest,tmpRequestState,fStageComplete);},fStageComplete=>{pResponse.send(tmpRequestState.RecordCount);this.log.requestCompletedSuccessfully(pRequest,tmpRequestState,'Undeleted '+tmpRequestState.RecordCount.Count+' records with ID '+tmpIDRecord+'.');return fStageComplete();}],pError=>{return this.ErrorHandler.handleErrorIfSet(pRequest,tmpRequestState,pResponse,pError,fNext);});};module.exports=doAPIEndpointUndelete;},{}],206:[function(require,module,exports){/**
5947
5968
  * Meadow Endpoint - Read a Record
@@ -5951,17 +5972,32 @@ tmpRequestState.RecordSearchCriteria=`${this.DAL.defaultIdentifier} = ${pRequest
5951
5972
  * Meadow Endpoint - Read a list of Records with a specified set of columns, distinct by those columns.
5952
5973
  */const marshalDistinctList=require('./Meadow-Marshal-DistinctList.js');const doAPIEndpointReadDistinct=function(pRequest,pResponse,fNext){let tmpRequestState=this.initializeRequestState(pRequest,'ReadDistinct');let fBehaviorInjector=pBehaviorHash=>{return fStageComplete=>{this.BehaviorInjection.runBehavior(pBehaviorHash,this,pRequest,tmpRequestState,fStageComplete);};};tmpRequestState.DistinctColumns;this.waterfall([fStageComplete=>{tmpRequestState.Query=this.DAL.query.setDistinct(true);/** @type {number | boolean} */let tmpCap=false;/** @type {number | boolean} */let tmpBegin=false;if(typeof pRequest.params.Begin==='string'||typeof pRequest.params.Begin==='number'){tmpBegin=parseInt(pRequest.params.Begin,10);}if(typeof pRequest.params.Cap==='string'||typeof pRequest.params.Cap==='number'){tmpCap=parseInt(pRequest.params.Cap,10);}else{//maximum number of records to return by default on Read queries. Override via "MeadowDefaultMaxCap" fable setting.
5953
5974
  tmpCap=this.settings['MeadowDefaultMaxCap']||250;}tmpRequestState.Query.setCap(tmpCap).setBegin(tmpBegin);if(typeof pRequest.params.Filter==='string'){// If a filter has been passed in, parse it and add the values to the query.
5954
- this.parseFilter(pRequest.params.Filter,tmpRequestState.Query);}else if(pRequest.params.Filter){tmpRequestState.Query.setFilter(pRequest.params.Filter);}if(typeof pRequest.params.Columns==='string'){tmpRequestState.DistinctColumns=pRequest.params.Columns.split(',');if(!tmpRequestState.DistinctColumns){return fStageComplete({Code:400,Message:'Columns to distinct on must be provided.'});}tmpRequestState.Query.setDataElements(tmpRequestState.DistinctColumns);}return fStageComplete();},fBehaviorInjector(`Reads-QueryConfiguration`),fStageComplete=>{this.DAL.doReads(tmpRequestState.Query,fStageComplete);},(pQuery,pRecords,fStageComplete)=>{if(pRecords.length<1){pRecords=[];}tmpRequestState.Records=pRecords;return fStageComplete();},fStageComplete=>{tmpRequestState.ResultRecords=marshalDistinctList.call(this,tmpRequestState.Records,pRequest,tmpRequestState.DistinctColumns);return fStageComplete();},fStageComplete=>{return this.doStreamRecordArray(pResponse,tmpRequestState.ResultRecords,fStageComplete);},fStageComplete=>{this.log.requestCompletedSuccessfully(pRequest,tmpRequestState,`Read a recordset distinct lite list with ${tmpRequestState.ResultRecords.length} results.`);return fStageComplete();}],pError=>{return this.ErrorHandler.handleErrorIfSet(pRequest,tmpRequestState,pResponse,pError,fNext);});};module.exports=doAPIEndpointReadDistinct;},{"./Meadow-Marshal-DistinctList.js":213}],208:[function(require,module,exports){/**
5975
+ this.parseFilter(pRequest.params.Filter,tmpRequestState.Query);}else if(pRequest.params.Filter){tmpRequestState.Query.setFilter(pRequest.params.Filter);}if(typeof pRequest.params.Columns==='string'){tmpRequestState.DistinctColumns=pRequest.params.Columns.split(',');if(!tmpRequestState.DistinctColumns){return fStageComplete({Code:400,Message:'Columns to distinct on must be provided.'});}tmpRequestState.Query.setDataElements(tmpRequestState.DistinctColumns);}return fStageComplete();},fBehaviorInjector(`Reads-QueryConfiguration`),fStageComplete=>{this.DAL.doReads(tmpRequestState.Query,fStageComplete);},(pQuery,pRecords,fStageComplete)=>{if(pRecords.length<1){pRecords=[];}tmpRequestState.Records=pRecords;return fStageComplete();},// Stage-specific post-op hook. Fires after DAL read but BEFORE
5976
+ // the records are projected to distinct-column shape, so
5977
+ // handlers can run against full rows. Separate from
5978
+ // Reads-PostOperation so registering one doesn't unintentionally
5979
+ // fire on the other. Hash matches the endpoint's action label
5980
+ // (initializeRequestState(..., 'ReadDistinct')).
5981
+ fBehaviorInjector(`ReadDistinct-PostOperation`),fStageComplete=>{tmpRequestState.ResultRecords=marshalDistinctList.call(this,tmpRequestState.Records,pRequest,tmpRequestState.DistinctColumns);return fStageComplete();},fStageComplete=>{return this.doStreamRecordArray(pResponse,tmpRequestState.ResultRecords,fStageComplete);},fStageComplete=>{this.log.requestCompletedSuccessfully(pRequest,tmpRequestState,`Read a recordset distinct lite list with ${tmpRequestState.ResultRecords.length} results.`);return fStageComplete();}],pError=>{return this.ErrorHandler.handleErrorIfSet(pRequest,tmpRequestState,pResponse,pError,fNext);});};module.exports=doAPIEndpointReadDistinct;},{"./Meadow-Marshal-DistinctList.js":213}],208:[function(require,module,exports){/**
5955
5982
  * Meadow Endpoint - Read a list of lite Records (for Drop-downs and such)
5956
5983
  */const marshalLiteList=require('./Meadow-Marshal-LiteList.js');const doAPIEndpointReadLite=function(pRequest,pResponse,fNext){let tmpRequestState=this.initializeRequestState(pRequest,'ReadsLite');let fBehaviorInjector=pBehaviorHash=>{return fStageComplete=>{this.BehaviorInjection.runBehavior(pBehaviorHash,this,pRequest,tmpRequestState,fStageComplete);};};this.waterfall([// 1a. Get the records
5957
5984
  fStageComplete=>{tmpRequestState.Query=this.DAL.query;// TODO: Limit the query to the columns we need for the templated expression
5958
5985
  /** @type {number | boolean} */var tmpCap=false;/** @type {number | boolean} */var tmpBegin=false;if(typeof pRequest.params.Begin==='string'||typeof pRequest.params.Begin==='number'){tmpBegin=parseInt(pRequest.params.Begin,10);}if(typeof pRequest.params.Cap==='string'||typeof pRequest.params.Cap==='number'){tmpCap=parseInt(pRequest.params.Cap,10);}else{//maximum number of records to return by default on Read queries. Override via "MeadowDefaultMaxCap" fable setting.
5959
5986
  tmpCap=this.settings['MeadowDefaultMaxCap']||250;}tmpRequestState.Query.setCap(tmpCap).setBegin(tmpBegin);if(typeof pRequest.params.Filter==='string'){// If a filter has been passed in, parse it and add the values to the query.
5960
- this.parseFilter(pRequest.params.Filter,tmpRequestState.Query);}else if(pRequest.params.Filter){tmpRequestState.Query.setFilter(pRequest.params.Filter);}return fStageComplete();},fBehaviorInjector(`Reads-QueryConfiguration`),fStageComplete=>{this.DAL.doReads(tmpRequestState.Query,fStageComplete);},(pQuery,pRecords,fStageComplete)=>{if(pRecords.length<1){pRecords=[];}tmpRequestState.RawRecords=pRecords;return fStageComplete();},fStageComplete=>{tmpRequestState.Records=marshalLiteList.call(this,tmpRequestState.RawRecords,pRequest,typeof pRequest.params.ExtraColumns==='string'?pRequest.params.ExtraColumns.split(','):[]);return fStageComplete();},fStageComplete=>{return this.doStreamRecordArray(pResponse,tmpRequestState.Records,fNext);},fStageComplete=>{this.log.requestCompletedSuccessfully(pRequest,tmpRequestState,`Read a recordset lite list with ${tmpRequestState.Records.length} results`);return fStageComplete();}],(pError,pResultRecords)=>{return this.ErrorHandler.handleErrorIfSet(pRequest,tmpRequestState,pResponse,pError,fNext);});};module.exports=doAPIEndpointReadLite;},{"./Meadow-Marshal-LiteList.js":214}],209:[function(require,module,exports){/**
5987
+ this.parseFilter(pRequest.params.Filter,tmpRequestState.Query);}else if(pRequest.params.Filter){tmpRequestState.Query.setFilter(pRequest.params.Filter);}return fStageComplete();},fBehaviorInjector(`Reads-QueryConfiguration`),fStageComplete=>{this.DAL.doReads(tmpRequestState.Query,fStageComplete);},(pQuery,pRecords,fStageComplete)=>{if(pRecords.length<1){pRecords=[];}tmpRequestState.RawRecords=pRecords;// Expose the loaded records under pRequestState.Records
5988
+ // so post-op hooks operate on the same shape regular
5989
+ // Reads uses. Marshalling to lite shape runs AFTER the
5990
+ // hook so hooks see full rows.
5991
+ tmpRequestState.Records=pRecords;return fStageComplete();},fBehaviorInjector(`ReadsLite-PostOperation`),fStageComplete=>{tmpRequestState.Records=marshalLiteList.call(this,tmpRequestState.RawRecords,pRequest,typeof pRequest.params.ExtraColumns==='string'?pRequest.params.ExtraColumns.split(','):[]);return fStageComplete();},fStageComplete=>{return this.doStreamRecordArray(pResponse,tmpRequestState.Records,fNext);},fStageComplete=>{this.log.requestCompletedSuccessfully(pRequest,tmpRequestState,`Read a recordset lite list with ${tmpRequestState.Records.length} results`);return fStageComplete();}],(pError,pResultRecords)=>{return this.ErrorHandler.handleErrorIfSet(pRequest,tmpRequestState,pResponse,pError,fNext);});};module.exports=doAPIEndpointReadLite;},{"./Meadow-Marshal-LiteList.js":214}],209:[function(require,module,exports){/**
5961
5992
  * Meadow Endpoint - Read the Max Value of a Column in a Set
5962
5993
  */const doAPIEndpointReadMax=function(pRequest,pResponse,fNext){let tmpRequestState=this.initializeRequestState(pRequest,'ReadMax');let fBehaviorInjector=pBehaviorHash=>{return fStageComplete=>{this.BehaviorInjection.runBehavior(pBehaviorHash,this,pRequest,tmpRequestState,fStageComplete);};};this.waterfall([fStageComplete=>{tmpRequestState.Query=this.DAL.query;return fStageComplete();},fStageComplete=>{tmpRequestState.ColumnName=pRequest.params.ColumnName;tmpRequestState.Query.setSort({Column:tmpRequestState.ColumnName,Direction:'Descending'});tmpRequestState.Query.setCap(1);return fStageComplete();},fBehaviorInjector(`ReadMax-QueryConfiguration`),fStageComplete=>{this.DAL.doRead(tmpRequestState.Query,fStageComplete);},(pQuery,pRecord,fStageComplete)=>{if(!pRecord){return fStageComplete(this.ErrorHandler.getError('Record not Found',404));}tmpRequestState.Record=pRecord;return fStageComplete();},fStageComplete=>{this.BehaviorInjection.runBehavior(`ReadMax-PostOperation`,this,pRequest,tmpRequestState,fStageComplete);},fStageComplete=>{this.log.requestCompletedSuccessfully(pRequest,tmpRequestState,`Read max record of ${this.DAL.scope} on ${tmpRequestState.ColumnName}`);pResponse.send(tmpRequestState.Record);}],pError=>{return this.ErrorHandler.handleErrorIfSet(pRequest,tmpRequestState,pResponse,pError,fNext);});};module.exports=doAPIEndpointReadMax;},{}],210:[function(require,module,exports){/**
5963
5994
  * Meadow Endpoint - Read a select list of Records (for Drop-downs and such)
5964
- */const doAPIEndpointReadSelectList=function(pRequest,pResponse,fNext){let tmpRequestState=this.initializeRequestState(pRequest,'ReadsBy');let fBehaviorInjector=pBehaviorHash=>{return fStageComplete=>{this.BehaviorInjection.runBehavior(pBehaviorHash,this,pRequest,tmpRequestState,fStageComplete);};};this.waterfall([fStageComplete=>{tmpRequestState.Query=this.DAL.query;/** @type {number | boolean} */var tmpCap=false;/** @type {number | boolean} */var tmpBegin=false;if(typeof pRequest.params.Begin==='string'||typeof pRequest.params.Begin==='number'){tmpBegin=parseInt(pRequest.params.Begin);}if(typeof pRequest.params.Cap==='string'||typeof pRequest.params.Cap==='number'){tmpCap=parseInt(pRequest.params.Cap);}else{tmpCap=this.settings['MeadowDefaultMaxCap']||250;}tmpRequestState.Query.setCap(tmpCap).setBegin(tmpBegin);if(typeof pRequest.params.Filter==='string'){this.parseFilter(pRequest.params.Filter,tmpRequestState.Query);}return fStageComplete();},fBehaviorInjector(`Reads-QueryConfiguration`),fStageComplete=>{this.DAL.doReads(tmpRequestState.Query,fStageComplete);},(pQuery,pRecords,fStageComplete)=>{if(pRecords.length<1){pRecords=[];}tmpRequestState.Records=pRecords;return fStageComplete();},fStageComplete=>{tmpRequestState.SelectList=[];for(var i=0;i<tmpRequestState.Records.length;i++){tmpRequestState.SelectList.push({Hash:tmpRequestState.Records[i][this.DAL.defaultIdentifier],Value:this.BehaviorInjection.processTemplate('SelectList',{Record:tmpRequestState.Records[i]},this.DAL.scope+' #<%= Record.'+this.DAL.defaultIdentifier+'%>')});}return fStageComplete();},fStageComplete=>{return this.doStreamRecordArray(pResponse,tmpRequestState.SelectList,fStageComplete);},fStageComplete=>{this.log.requestCompletedSuccessfully(pRequest,tmpRequestState,`Read a recordset lite list with ${tmpRequestState.SelectList.length} results.`);return fStageComplete();}],(pError,pResultRecords)=>{return this.ErrorHandler.handleErrorIfSet(pRequest,tmpRequestState,pResponse,pError,fNext);});};module.exports=doAPIEndpointReadSelectList;},{}],211:[function(require,module,exports){/**
5995
+ */const doAPIEndpointReadSelectList=function(pRequest,pResponse,fNext){let tmpRequestState=this.initializeRequestState(pRequest,'ReadsBy');let fBehaviorInjector=pBehaviorHash=>{return fStageComplete=>{this.BehaviorInjection.runBehavior(pBehaviorHash,this,pRequest,tmpRequestState,fStageComplete);};};this.waterfall([fStageComplete=>{tmpRequestState.Query=this.DAL.query;/** @type {number | boolean} */var tmpCap=false;/** @type {number | boolean} */var tmpBegin=false;if(typeof pRequest.params.Begin==='string'||typeof pRequest.params.Begin==='number'){tmpBegin=parseInt(pRequest.params.Begin);}if(typeof pRequest.params.Cap==='string'||typeof pRequest.params.Cap==='number'){tmpCap=parseInt(pRequest.params.Cap);}else{tmpCap=this.settings['MeadowDefaultMaxCap']||250;}tmpRequestState.Query.setCap(tmpCap).setBegin(tmpBegin);if(typeof pRequest.params.Filter==='string'){this.parseFilter(pRequest.params.Filter,tmpRequestState.Query);}return fStageComplete();},fBehaviorInjector(`Reads-QueryConfiguration`),fStageComplete=>{this.DAL.doReads(tmpRequestState.Query,fStageComplete);},(pQuery,pRecords,fStageComplete)=>{if(pRecords.length<1){pRecords=[];}tmpRequestState.Records=pRecords;return fStageComplete();},// Stage-specific post-op hook. Fires after DAL read but
5996
+ // BEFORE the records are projected to select-list
5997
+ // (Hash/Value) shape, so handlers can run against full
5998
+ // rows. Separate from Reads-PostOperation so registering
5999
+ // one doesn't unintentionally fire on the other.
6000
+ fBehaviorInjector(`ReadSelectList-PostOperation`),fStageComplete=>{tmpRequestState.SelectList=[];for(var i=0;i<tmpRequestState.Records.length;i++){tmpRequestState.SelectList.push({Hash:tmpRequestState.Records[i][this.DAL.defaultIdentifier],Value:this.BehaviorInjection.processTemplate('SelectList',{Record:tmpRequestState.Records[i]},this.DAL.scope+' #<%= Record.'+this.DAL.defaultIdentifier+'%>')});}return fStageComplete();},fStageComplete=>{return this.doStreamRecordArray(pResponse,tmpRequestState.SelectList,fStageComplete);},fStageComplete=>{this.log.requestCompletedSuccessfully(pRequest,tmpRequestState,`Read a recordset lite list with ${tmpRequestState.SelectList.length} results.`);return fStageComplete();}],(pError,pResultRecords)=>{return this.ErrorHandler.handleErrorIfSet(pRequest,tmpRequestState,pResponse,pError,fNext);});};module.exports=doAPIEndpointReadSelectList;},{}],211:[function(require,module,exports){/**
5965
6001
  * Meadow Endpoint - Read a Set of Records
5966
6002
  */const doAPIEndpointReads=function(pRequest,pResponse,fNext){let tmpRequestState=this.initializeRequestState(pRequest,'Reads');let fBehaviorInjector=pBehaviorHash=>{return fStageComplete=>{this.BehaviorInjection.runBehavior(pBehaviorHash,this,pRequest,tmpRequestState,fStageComplete);};};this.waterfall([fStageComplete=>{tmpRequestState.Query=this.DAL.query;/** @type {number | boolean} */var tmpCap=false;/** @type {number | boolean} */var tmpBegin=false;if(typeof pRequest.params.Begin==='string'||typeof pRequest.params.Begin==='number'){tmpBegin=parseInt(pRequest.params.Begin);}if(typeof pRequest.params.Cap==='string'||typeof pRequest.params.Cap==='number'){tmpCap=parseInt(pRequest.params.Cap);}else{tmpCap=this.settings['MeadowDefaultMaxCap']||250;}tmpRequestState.Query.setCap(tmpCap).setBegin(tmpBegin);if(typeof pRequest.params.Filter==='string'){// If a filter has been passed in, parse it and add the values to the query.
5967
6003
  this.parseFilter(pRequest.params.Filter,tmpRequestState.Query);}else if(pRequest.params.Filter){tmpRequestState.Query.setFilter(pRequest.params.Filter);}return fStageComplete();},fBehaviorInjector(`Reads-QueryConfiguration`),fStageComplete=>{this.DAL.doReads(tmpRequestState.Query,fStageComplete);},(pQuery,pRecords,fStageComplete)=>{if(!pRecords){return fStageComplete(this.ErrorHandler.getError('No records found.',404));}tmpRequestState.Records=pRecords;return fStageComplete();},fBehaviorInjector(`Reads-PostOperation`),fStageComplete=>{this.doStreamRecordArray(pResponse,tmpRequestState.Records,fStageComplete);},fStageComplete=>{this.log.requestCompletedSuccessfully(pRequest,tmpRequestState,'Read a list of records.');return fStageComplete();}],pError=>{return this.ErrorHandler.handleErrorIfSet(pRequest,tmpRequestState,pResponse,pError,fNext);});};module.exports=doAPIEndpointReads;},{}],212:[function(require,module,exports){/**
@@ -6002,7 +6038,14 @@ if(!pRequest.JSONSchema){tmpRequestState.JSONSchema=this.extend({},this.DAL.json
6002
6038
  let tmpRequestState=this.cloneAsyncSafeRequestState(pRequestState,'doUpdate');let fBehaviorInjector=pBehaviorHash=>{return fStageComplete=>{this.BehaviorInjection.runBehavior(pBehaviorHash,this,pRequest,tmpRequestState,fStageComplete);};};// If there is not a default identifier or cached record, fail
6003
6039
  if(pRecordToModify[this.DAL.defaultIdentifier]<1&&typeof pOptionalCachedUpdatingRecord==='undefined'){return fCallback('Record update failure - a valid record ID is required in the passed-in record.');}if(!Array.isArray(tmpRequestState.ParentRequestState.UpdatedRecords)){tmpRequestState.ParentRequestState.UpdatedRecords=[];}this.waterfall([fStageComplete=>{tmpRequestState.RecordToModify=pRecordToModify;if(typeof pOptionalCachedUpdatingRecord!=='undefined'){// Use the cached updating record instead of reading a record.
6004
6040
  tmpRequestState.OriginalRecord=pOptionalCachedUpdatingRecord;return fStageComplete();}else{tmpRequestState.Query=this.DAL.query;tmpRequestState.Query.addFilter(this.DAL.defaultIdentifier,tmpRequestState.RecordToModify[this.DAL.defaultIdentifier]);// Load the record so we can do security checks on it
6005
- this.DAL.doRead(tmpRequestState.Query,(pError,pQuery,pRecord)=>{if(pError){return fStageComplete(pError);}if(!pRecord){return fStageComplete(this.ErrorHandler.getError('Record not Found',404));}tmpRequestState.Record=pRecord;return fStageComplete();});}},fStageComplete=>{tmpRequestState.Query=this.DAL.query;return fStageComplete();},fBehaviorInjector(`Update-PreOperation`),fStageComplete=>{tmpRequestState.Query.setIDUser(tmpRequestState.SessionData.UserID);tmpRequestState.Query.addRecord(tmpRequestState.RecordToModify);return fStageComplete();},fBehaviorInjector(`Update-QueryConfiguration`),fStageComplete=>{this.DAL.doUpdate(tmpRequestState.Query,(pError,pQuery,pReadQuery,pRecord)=>{if(pError){if(typeof pError=='string'){return fStageComplete(this.ErrorHandler.getError(pError,500));}else{return fStageComplete(pError);}}if(!pRecord){return fStageComplete(this.ErrorHandler.getError(`Error in DAL Update: No record returned from persistence engine.`,500));}tmpRequestState.Record=pRecord;return fStageComplete();});},fStageComplete=>{return this.BehaviorInjection.runBehavior(`Update-PostOperation`,this,pRequest,tmpRequestState,fStageComplete);},fStageComplete=>{tmpRequestState.ParentRequestState.UpdatedRecords.push(tmpRequestState.Record);this.log.requestCompletedSuccessfully(pRequest,tmpRequestState,`Updated record with ID ${tmpRequestState.Record[this.DAL.defaultIdentifier]}`);return fStageComplete();}],pError=>{if(pError){// Ensure we have a record object to attach the error to
6041
+ this.DAL.doRead(tmpRequestState.Query,(pError,pQuery,pRecord)=>{if(pError){return fStageComplete(pError);}if(!pRecord){return fStageComplete(this.ErrorHandler.getError('Record not Found',404));}tmpRequestState.Record=pRecord;// Alias the loaded pre-update row under an
6042
+ // unambiguous name. pRequestState.Record gets
6043
+ // overwritten with the POST-update row later in
6044
+ // this waterfall; OriginalRecord preserves the
6045
+ // PRE-update reference for post-op hooks that
6046
+ // need to compare before/after values (change
6047
+ // logs, customer-boundary checks, etc.).
6048
+ tmpRequestState.OriginalRecord=pRecord;return fStageComplete();});}},fStageComplete=>{tmpRequestState.Query=this.DAL.query;return fStageComplete();},fBehaviorInjector(`Update-PreOperation`),fStageComplete=>{tmpRequestState.Query.setIDUser(tmpRequestState.SessionData.UserID);tmpRequestState.Query.addRecord(tmpRequestState.RecordToModify);return fStageComplete();},fBehaviorInjector(`Update-QueryConfiguration`),fStageComplete=>{this.DAL.doUpdate(tmpRequestState.Query,(pError,pQuery,pReadQuery,pRecord)=>{if(pError){if(typeof pError=='string'){return fStageComplete(this.ErrorHandler.getError(pError,500));}else{return fStageComplete(pError);}}if(!pRecord){return fStageComplete(this.ErrorHandler.getError(`Error in DAL Update: No record returned from persistence engine.`,500));}tmpRequestState.Record=pRecord;return fStageComplete();});},fStageComplete=>{return this.BehaviorInjection.runBehavior(`Update-PostOperation`,this,pRequest,tmpRequestState,fStageComplete);},fStageComplete=>{tmpRequestState.ParentRequestState.UpdatedRecords.push(tmpRequestState.Record);this.log.requestCompletedSuccessfully(pRequest,tmpRequestState,`Updated record with ID ${tmpRequestState.Record[this.DAL.defaultIdentifier]}`);return fStageComplete();}],pError=>{if(pError){// Ensure we have a record object to attach the error to
6006
6049
  if(tmpRequestState.Record){tmpRequestState.Record.Error=pError;}else{tmpRequestState.Record={Error:pError};}tmpRequestState.ParentRequestState.RecordUpdateError=true;tmpRequestState.ParentRequestState.RecordUpdateErrorObject=pError;tmpRequestState.ParentRequestState.UpdatedRecords.push(tmpRequestState.Record);}return fCallback();});};module.exports=doUpdate;},{}],221:[function(require,module,exports){/**
6007
6050
  * Meadow Endpoint - Upsert a set of Records
6008
6051
  */const doUpsert=require('./Meadow-Operation-Upsert.js');const marshalLiteList=require('../read/Meadow-Marshal-LiteList.js');const doAPIEndpointUpserts=function(pRequest,pResponse,fNext){let tmpRequestState=this.initializeRequestState(pRequest,'UpsertBulk');let fBehaviorInjector=pBehaviorHash=>{return fStageComplete=>{this.BehaviorInjection.runBehavior(pBehaviorHash,this,pRequest,tmpRequestState,fStageComplete);};};tmpRequestState.CreatedRecords=[];tmpRequestState.UpdatedRecords=[];tmpRequestState.UpsertedRecords=[];tmpRequestState.ErrorRecords=[];this.waterfall([fStageComplete=>{if(!Array.isArray(pRequest.body)){return fStageComplete(this.ErrorHandler.getError(`Record bulk upsert failure - a valid array of records is required.`,500));}tmpRequestState.BulkRecords=pRequest.body;return fStageComplete();},fBehaviorInjector(`UpsertBulk-PreOperation`),fStageComplete=>{this.eachLimit(tmpRequestState.BulkRecords,1,(pRecord,fCallback)=>{doUpsert.call(this,pRecord,pRequest,tmpRequestState,pResponse,fCallback);},fStageComplete);},fBehaviorInjector(`UpsertBulk-PostOperation`),fStageComplete=>{return this.doStreamRecordArray(pResponse,marshalLiteList.call(this,tmpRequestState.UpsertedRecords,pRequest),fStageComplete);},fStageComplete=>{this.log.requestCompletedSuccessfully(pRequest,tmpRequestState,`Bulk upsert complete -- ${tmpRequestState.UpsertedRecords.length} records processed`);return fStageComplete();}],pError=>{return this.ErrorHandler.handleErrorIfSet(pRequest,tmpRequestState,pResponse,pError,fNext);});};module.exports=doAPIEndpointUpserts;},{"../read/Meadow-Marshal-LiteList.js":214,"./Meadow-Operation-Upsert.js":223}],222:[function(require,module,exports){/**