text: //  ██╗   ██╗██████╗ ██████╗  █████╗ ████████╗███████╗     █████╗  ██████╗████████╗██╗ ██████╗ ███╗   ██╗
  //  ██║   ██║██╔══██╗██╔══██╗██╔══██╗╚══██╔══╝██╔════╝    ██╔══██╗██╔════╝╚══██╔══╝██║██╔═══██╗████╗  ██║
  //  ██║   ██║██████╔╝██║  ██║███████║   ██║   █████╗      ███████║██║        ██║   ██║██║   ██║██╔██╗ ██║
  //  ██║   ██║██╔═══╝ ██║  ██║██╔══██║   ██║   ██╔══╝      ██╔══██║██║        ██║   ██║██║   ██║██║╚██╗██║
  //  ╚██████╔╝██║     ██████╔╝██║  ██║   ██║   ███████╗    ██║  ██║╚██████╗   ██║   ██║╚██████╔╝██║ ╚████║
  //   ╚═════╝ ╚═╝     ╚═════╝ ╚═╝  ╚═╝   ╚═╝   ╚══════╝    ╚═╝  ╚═╝ ╚═════╝   ╚═╝   ╚═╝ ╚═════╝ ╚═╝  ╚═══╝
  //
  
  module.exports = require('machine').build({
  
  
    friendlyName: 'Update',
  
  
    description: 'Update record(s) in the database based on a query criteria.',
  
  
    inputs: {
  
      datastore: {
        description: 'The datastore to use for connections.',
        extendedDescription: 'Datastores represent the config and manager required to obtain an active database connection.',
        required: true,
        readOnly: true,
        type: 'ref'
      },
  
      models: {
        description: 'An object containing all of the model definitions that have been registered.',
        required: true,
        type: 'ref'
      },
  
      query: {
        description: 'A valid stage three Waterline query.',
        required: true,
        type: 'ref'
      }
  
    },
  
  
    exits: {
  
      success: {
        description: 'The records were successfully updated.',
        outputVariableName: 'records',
        outputType: 'ref'
      },
  
      invalidDatastore: {
        description: 'The datastore used is invalid. It is missing key pieces.'
      },
  
      badConnection: {
        friendlyName: 'Bad connection',
        description: 'A connection either could not be obtained or there was an error using the connection.'
      },
  
      notUnique: {
        friendlyName: 'Not Unique',
        outputType: 'ref'
      }
  
    },
  
  
    fn: function update(inputs, exits) {
      // Dependencies
      var _ = require('@sailshq/lodash');
      var WLUtils = require('waterline-utils');
      var Helpers = require('./private');
      var Converter = WLUtils.query.converter;
  
  
      // Store the Query input for easier access
      var query = inputs.query;
      query.criteria = _.omit(query.criteria, ['limit', 'skip', 'sort']);
      query.meta = query.meta || {};
  
  
      // Find the model definition
      var model = inputs.models[query.using];
      if (!model) {
        return exits.invalidDatastore();
      }
  
  
      // Build up a faux ORM instance for processing records
      var orm = {
        collections: inputs.models
      };
  
  
      // Set a flag if a leased connection from outside the adapter was used or not.
      var leased = _.has(query.meta, 'leasedConnection');
  
      // Set a flag to determine if records are being returned
      var fetchRecords = false;
  
  
      var schemaName = Helpers.query.schemaName(inputs, query);
  
  
      //  ┌─┐┬─┐┌─┐  ┌─┐┬─┐┌─┐┌─┐┌─┐┌─┐┌─┐  ┌─┐┌─┐┌─┐┬ ┬  ┬─┐┌─┐┌─┐┌─┐┬─┐┌┬┐
      //  ├─┘├┬┘├┤───├─┘├┬┘│ ││  ├┤ └─┐└─┐  ├┤ ├─┤│  ├─┤  ├┬┘├┤ │  │ │├┬┘ ││
      //  ┴  ┴└─└─┘  ┴  ┴└─└─┘└─┘└─┘└─┘└─┘  └─┘┴ ┴└─┘┴ ┴  ┴└─└─┘└─┘└─┘┴└──┴┘
      try {
        Helpers.query.preProcessEachRecord({
          records: [query.valuesToSet],
          identity: model.identity,
          orm: orm
        });
      } catch (e) {
        return exits.error(e);
      }
  
  
      //  ╔═╗╔═╗╔╗╔╦  ╦╔═╗╦═╗╔╦╗  ┌┬┐┌─┐  ┌─┐┌┬┐┌─┐┌┬┐┌─┐┌┬┐┌─┐┌┐┌┌┬┐
      //  ║  ║ ║║║║╚╗╔╝║╣ ╠╦╝ ║    │ │ │  └─┐ │ ├─┤ │ ├┤ │││├┤ │││ │
      //  ╚═╝╚═╝╝╚╝ ╚╝ ╚═╝╩╚═ ╩    ┴ └─┘  └─┘ ┴ ┴ ┴ ┴ └─┘┴ ┴└─┘┘└┘ ┴
      // Convert the Waterline criteria into a Waterline Query Statement. This
      // turns it into something that is declarative and can be easily used to
      // build a SQL query.
      // See: https://github.com/treelinehq/waterline-query-docs for more info
      // on Waterline Query Statements.
      var statement;
      try {
        statement = Converter({
          model: query.using,
          method: 'update',
          criteria: query.criteria,
          values: query.valuesToSet,
          opts: {
            schema: schemaName
          }
        });
      } catch (e) {
        return exits.error(e);
      }
  
  
      //  ╔╦╗╔═╗╔╦╗╔═╗╦═╗╔╦╗╦╔╗╔╔═╗  ┬ ┬┬ ┬┬┌─┐┬ ┬  ┬  ┬┌─┐┬  ┬ ┬┌─┐┌─┐
      //   ║║║╣  ║ ║╣ ╠╦╝║║║║║║║║╣   │││├─┤││  ├─┤  └┐┌┘├─┤│  │ │├┤ └─┐
      //  ═╩╝╚═╝ ╩ ╚═╝╩╚═╩ ╩╩╝╚╝╚═╝  └┴┘┴ ┴┴└─┘┴ ┴   └┘ ┴ ┴┴─┘└─┘└─┘└─┘
      //  ┌┬┐┌─┐  ┬─┐┌─┐┌┬┐┬ ┬┬─┐┌┐┌
      //   │ │ │  ├┬┘├┤  │ │ │├┬┘│││
      //   ┴ └─┘  ┴└─└─┘ ┴ └─┘┴└─┘└┘
      if (_.has(query.meta, 'fetch') && query.meta.fetch) {
        fetchRecords = true;
  
        // Add the MsSql output * piece to the statement to prevent the
        // overhead of running two additional queries.
        statement.returning = '*';
      }
  
  
      //  ╔═╗╔═╗╔╦╗╔═╗╦╦  ╔═╗  ┌─┐ ┬ ┬┌─┐┬─┐┬ ┬
      //  ║  ║ ║║║║╠═╝║║  ║╣   │─┼┐│ │├┤ ├┬┘└┬┘
      //  ╚═╝╚═╝╩ ╩╩  ╩╩═╝╚═╝  └─┘└└─┘└─┘┴└─ ┴
      // Compile statement into a native query.
      var compiledQuery;
      try {
        compiledQuery = Helpers.query.compileStatement(statement);
      } catch (e) {
        return exits.error(e);
      }
  
  
      //  ╔═╗╔═╗╔═╗╦ ╦╔╗╔  ┌─┐┌─┐┌┐┌┌┐┌┌─┐┌─┐┌┬┐┬┌─┐┌┐┌
      //  ╚═╗╠═╝╠═╣║║║║║║  │  │ │││││││├┤ │   │ ││ ││││
      //  ╚═╝╩  ╩ ╩╚╩╝╝╚╝  └─┘└─┘┘└┘┘└┘└─┘└─┘ ┴ ┴└─┘┘└┘
      //  ┌─┐┬─┐  ┬ ┬┌─┐┌─┐  ┬  ┌─┐┌─┐┌─┐┌─┐┌┬┐  ┌─┐┌─┐┌┐┌┌┐┌┌─┐┌─┐┌┬┐┬┌─┐┌┐┌
      //  │ │├┬┘  │ │└─┐├┤   │  ├┤ ├─┤└─┐├┤  ││  │  │ │││││││├┤ │   │ ││ ││││
      //  └─┘┴└─  └─┘└─┘└─┘  ┴─┘└─┘┴ ┴└─┘└─┘─┴┘  └─┘└─┘┘└┘┘└┘└─┘└─┘ ┴ ┴└─┘┘└┘
      // Spawn a new connection for running queries on.
      Helpers.connection.spawnOrLeaseConnection(inputs.datastore, query.meta, function spawnConnectionCb(err, connection) {
        if (err) {
          return exits.badConnection(err);
        }
  
  
        //  ╦═╗╦ ╦╔╗╔  ┬ ┬┌─┐┌┬┐┌─┐┌┬┐┌─┐  ┌─┐ ┬ ┬┌─┐┬─┐┬ ┬
        //  ╠╦╝║ ║║║║  │ │├─┘ ││├─┤ │ ├┤   │─┼┐│ │├┤ ├┬┘└┬┘
        //  ╩╚═╚═╝╝╚╝  └─┘┴  ─┴┘┴ ┴ ┴ └─┘  └─┘└└─┘└─┘┴└─ ┴
        // Insert the record and return the new values
        Helpers.query.modifyRecord({
          connection: connection,
          query: compiledQuery.nativeQuery,
          valuesToEscape: compiledQuery.valuesToEscape,
          leased: leased,
          fetchRecords: fetchRecords
        },
  
        function modifyRecordCb(err, updatedRecords) {
          // If there was an error the helper takes care of closing the connection
          // if a connection was spawned internally.
          if (err) {
            if (err.footprint && err.footprint.identity === 'notUnique') {
              return exits.notUnique(err);
            }
  
            return exits.error(err);
          }
  
          // Release the connection if needed.
          Helpers.connection.releaseConnection(connection, leased, function releaseCb() {
            if (fetchRecords) {
              // Process each record to normalize output
              try {
                Helpers.query.processEachRecord({
                  records: updatedRecords,
                  identity: model.identity,
                  orm: orm
                });
              } catch (e) {
                return exits.error(e);
              }
  
              return exits.success({ records: updatedRecords });
            }
  
            return exits.success();
          }); // </ .releaseConnection(); >
        }); // </ .modifyRecord(); >
      }); // </ spawnConnection >
    }
  });
  