crud (method, ...args) {
    const config = this.lifecycleMethods[method]
    if (!config) {
      throw utils.err(`${DOMAIN}#crud`, method)(404, 'method')
    }

    const upper = `${method.charAt(0).toUpperCase()}${method.substr(1)}`
    const before = `before${upper}`
    const after = `after${upper}`

    let op

    // Default values for arguments
    config.defaults.forEach((value, i) => {
      if (args[i] === undefined) {
        args[i] = utils.copy(value)
      }
    })

    const opts = args[args.length - 1]

    // Fill in "opts" with the Mapper's configuration
    utils._(opts, this)
    const adapter = opts.adapter = this.getAdapterName(opts)

    // before lifecycle hook
    op = opts.op = before
    return utils.resolve(this[op](...args)).then((_value) => {
      if (args[config.beforeAssign] !== undefined) {
        // Allow for re-assignment from lifecycle hook
        args[config.beforeAssign] = _value === undefined ? args[config.beforeAssign] : _value
      }
      // Now delegate to the adapter
      op = opts.op = method
      args = config.adapterArgs ? config.adapterArgs(this, ...args) : args
      this.dbg(op, ...args)
      return utils.resolve(this.getAdapter(adapter)[op](this, ...args))
    }).then((result) => {
      // force noValidate on find/findAll
      const noValidate = /find/.test(op) || opts.noValidate
      const _opts = Object.assign({}, opts, { noValidate })

      result = this._end(result, _opts, !!config.skip)
      args.push(result)
      // after lifecycle hook
      op = opts.op = after
      return utils.resolve(this[op](...args)).then((_result) => {
        // Allow for re-assignment from lifecycle hook
        return _result === undefined ? result : _result
      })
    })
  }
Lifecycle invocation method. You probably won't call this method directly.

@method Mapper#crud
@param {string} method Name of the lifecycle method to invoke.
@param {...*} args Arguments to pass to the lifecycle method.
@returns {Promise}
@since 3.0.0