join(joinName, comparisonsArray, orderBy, count, offset) {

    // FIXME: validate orderBy
    orderBy = orderBy || '';
    count = Math.max(0, count | 0);
    offset = Math.max(0, offset | 0);

    if (!(comparisonsArray instanceof Array)) {
      comparisonsArray = [].slice.call(arguments, 1);
    }

    let relationship = this.Model.relationships().findExplicit(joinName);
    if (!relationship) {
      throw new Error(`Model ${this.Model.name} does not have relationship "${joinName}".`);
    }

    let composer = this;
    while (composer) {
      if (composer._command && composer._command.type === 'join' && composer._command.data.name === joinName) {
        return this;
      }
      composer = composer._parent;
    }

    let joinData = relationship.joins();
    joinData = joinData.map((joinItem, i) => {
      let joinNameComponents = joinName.split('__');
      joinItem.joinAlias = joinNameComponents.slice(0, i + 1).join('__');
      joinItem.prevAlias = joinNameComponents.slice(0, i).join('__');
      return joinItem;
    });

    joinData[joinData.length - 1].multiFilter = this.db.adapter.createMultiFilter(
      joinName,
      comparisonsArray
        .map(comparisons => this.__parseComparisons__(comparisons, relationship.getModel()))
        .filter(f => f.length)
    );

    // FIXME: implement properly
    joinData[joinData.length - 1].orderBy = orderBy;
    joinData[joinData.length - 1].offset = offset;
    joinData[joinData.length - 1].count = count;

    this._command = {
      type: 'join',
      data: {
        name: joinName,
        joinData: joinData
      }
    };

    return new Composer(this.Model, this);

  }
Join in a relationship.
@param {string} joinName The name of the joined relationship
@param {array} comparisonsArray comparisons to perform on this join (can be overloaded)