2017-08-24 13:03:44 -04:00
|
|
|
/**
|
|
|
|
* Initialize document data for a given Program
|
|
|
|
*
|
2019-08-30 09:41:33 -04:00
|
|
|
* Copyright (C) 2010-2019 R-T Specialty, LLC.
|
2017-08-24 13:03:44 -04:00
|
|
|
*
|
|
|
|
* This file is part of the Liza Data Collection Framework.
|
|
|
|
*
|
|
|
|
* liza is free software: you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
|
|
* (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
|
|
|
|
'use strict';
|
|
|
|
|
|
|
|
const { Class } = require( 'easejs' );
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Initialize document bucket data for given Programs
|
|
|
|
*
|
|
|
|
* A default bucket is initialized considering certain aspects of a given
|
|
|
|
* Program (see `#init`).
|
|
|
|
*
|
|
|
|
* TODO: This should really contain _all_ of the init code, extracted from
|
|
|
|
* Server, but time did not permit. Refactoring can continue at a later date.
|
|
|
|
*/
|
|
|
|
module.exports = Class( 'ProgramInit',
|
|
|
|
{
|
|
|
|
/**
|
|
|
|
* Initialize document bucket data for `program`
|
|
|
|
*
|
|
|
|
* The original object `doc_data` will be modified by reference and
|
|
|
|
* returned. If `doc_data` evaluates to `false`, an empty object will
|
|
|
|
* be returned. Any other input results in undefined behavior.
|
|
|
|
*
|
|
|
|
* Note: This implementation used to cache default bucket objects, but
|
|
|
|
* doing so risks causing subtle and nasty bugs if the system modifies
|
|
|
|
* the default bucket object somewhere down the line, thereby affecting
|
|
|
|
* all documents going forward.
|
|
|
|
*
|
|
|
|
* @param {Program} program source program
|
|
|
|
* @param {Object} doc_data existing document data, if any
|
|
|
|
*
|
|
|
|
* @return {Object} `doc_data` modified
|
|
|
|
*/
|
|
|
|
'public init'( program, doc_data )
|
|
|
|
{
|
2018-06-19 09:57:50 -04:00
|
|
|
const data = doc_data || {};
|
2018-11-12 14:53:58 -05:00
|
|
|
|
|
|
|
const {
|
|
|
|
defaults = {},
|
|
|
|
meta: { groups = {}, qtypes = {} },
|
|
|
|
} = program;
|
2018-06-08 15:43:51 -04:00
|
|
|
|
2018-06-15 13:35:06 -04:00
|
|
|
Object.keys( program.groupExclusiveFields ).forEach( group =>
|
2018-06-08 15:43:51 -04:00
|
|
|
{
|
2018-06-19 09:57:50 -04:00
|
|
|
let i = program.groupExclusiveFields[ group ].length;
|
2018-06-08 15:43:51 -04:00
|
|
|
|
2018-06-19 09:57:50 -04:00
|
|
|
while ( i-- )
|
2018-06-08 15:43:51 -04:00
|
|
|
{
|
2018-11-12 14:53:58 -05:00
|
|
|
const field = program.groupExclusiveFields[ group ][ i ];
|
2018-06-19 09:57:50 -04:00
|
|
|
const default_value = defaults[ field ];
|
2018-06-08 15:43:51 -04:00
|
|
|
|
2018-11-12 14:53:58 -05:00
|
|
|
// generated questions with no types should never be part of
|
|
|
|
// the bucket
|
|
|
|
if ( !this._isKnownType( qtypes[ field ] ) )
|
|
|
|
{
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( !defaults.hasOwnProperty( field ) )
|
2018-06-08 15:43:51 -04:00
|
|
|
{
|
2018-06-15 13:35:06 -04:00
|
|
|
continue;
|
|
|
|
}
|
2018-06-12 14:52:36 -04:00
|
|
|
|
2018-06-15 13:35:06 -04:00
|
|
|
// Initialize with existing document data if any
|
2018-06-08 15:43:51 -04:00
|
|
|
|
2018-06-15 13:35:06 -04:00
|
|
|
// If no document data, initialize with default value
|
|
|
|
if ( data[ field ] === undefined )
|
|
|
|
{
|
2018-06-19 09:57:50 -04:00
|
|
|
data[ field ] = [ default_value ];
|
2018-06-15 13:35:06 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
// If min rows on the group is greater than the data
|
|
|
|
// currently in the bucket, then populate the rest
|
|
|
|
// of the data with the default data until the
|
|
|
|
// arrays are the same length
|
|
|
|
if ( groups.hasOwnProperty( group ) &&
|
|
|
|
data[ field ].length < groups[ group ].min )
|
|
|
|
{
|
|
|
|
let index = data[ field ].length;
|
2018-06-12 15:20:14 -04:00
|
|
|
|
2018-06-15 13:35:06 -04:00
|
|
|
while ( index < groups[ group ].min )
|
|
|
|
{
|
2018-06-19 09:57:50 -04:00
|
|
|
data[ field ][ index ] = default_value;
|
2018-06-15 13:35:06 -04:00
|
|
|
index++;
|
2018-06-08 15:43:51 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2018-11-12 14:53:58 -05:00
|
|
|
} );
|
2018-06-08 15:43:51 -04:00
|
|
|
|
|
|
|
return Promise.resolve( data );
|
2017-08-24 13:03:44 -04:00
|
|
|
},
|
2018-11-12 14:53:58 -05:00
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Determine whether question type QTYPE is known
|
|
|
|
*
|
2018-11-19 11:10:16 -05:00
|
|
|
* This assumes that the type is known unless QTYPE.type is
|
|
|
|
* "undefined". Ancient versions (pre-"liza") represented QTYPE as a
|
|
|
|
* string rather than an object.
|
2018-11-12 14:53:58 -05:00
|
|
|
*
|
2018-11-19 11:10:16 -05:00
|
|
|
* @param {Object|string} qtype type data for question
|
2018-11-12 14:53:58 -05:00
|
|
|
*
|
|
|
|
* @return {boolean} whether type is known
|
|
|
|
*/
|
|
|
|
'private _isKnownType'( qtype )
|
|
|
|
{
|
2018-11-19 11:10:16 -05:00
|
|
|
// this was a string in ancient versions (pre-"liza")
|
|
|
|
const type = ( typeof qtype === 'object' )
|
|
|
|
? qtype.type
|
|
|
|
: qtype;
|
|
|
|
|
|
|
|
return ( typeof type === 'string' )
|
|
|
|
&& ( type !== 'undefined' );
|
2018-11-12 14:53:58 -05:00
|
|
|
},
|
2017-08-24 13:03:44 -04:00
|
|
|
} );
|