
import Expression from './base'
import Literal from './literal'
import Criteria from './criteria'

/**
 * @class JoinExpression
 */
export default class Join extends Expression {
  /**
   * @param {Any} table
   * @param {String} type
   * @constructor
   */
  constructor (table, type = 'inner') {
    super()

    this.type = type
    this.columns = []
    this.table = table
    this.conditions = []
  }

  /**
   * @param {Any} table
   * @param {String} type
   * @returns {Expression}
   */
  static from (table, type = 'inner') {
    if (table instanceof Join) return table

    if (table instanceof Literal) return table

    return new Join(Literal.from(table), type)
  }

  /**
   * @param {Compiler} compiler
   * @returns {String}
   */
  compile (compiler) {
    return compiler.compileJoin(this)
  }

  /**
   * @returns {Join}
   * @override
   */
  clone () {
    return new Join(this.table, this.type)
      .setColumns(this.columns.slice())
      .setConditions(this.conditions.slice())
  }

  /**
   * @returns {Array}
   */
  getColumns () {
    return this.columns
  }

  /**
   * @returns {Boolean}
   */
  hasColumns () {
    return this.columns.length > 0
  }

  /**
   * @returns {Join}
   */
  resetColumns () {
    return this.setColumns([])
  }

  /**
   * @param {Array} value
   * @returns {Join}
   */
  setColumns (value) {
    this.columns = value
    return this
  }

  /**
   * @param {String} expr
   * @param {Array} args
   * @returns {Join}
   */
  where (expr, ...args) {
    this.getConditions().push(Criteria.from(...arguments))
    return this
  }

  /**
   * @param {String} expr
   * @param {Array} args
   * @returns {Join}
   */
  orWhere (expr, ...args) {
    this.getConditions().push(Criteria.from(...arguments).or())
    return this
  }

  /**
   * @param {String} expr
   * @param {Array} args
   * @returns {Join}
   */
  whereNot (expr, ...args) {
    this.getConditions().push(Criteria.from(...arguments).not())
    return this
  }

  /**
   * @param {String} expr
   * @param {Array} args
   * @returns {Join}
   */
  orWhereNot (expr, ...args) {
    this.getConditions().push(Criteria.from(...arguments).or().not())
    return this
  }

  /**
   * @returns {Boolean}
   */
  hasConditions () {
    return this.conditions.length > 0
  }

  /**
   * @param {Array} value
   * @returns {Join}
   */
  setConditions (value) {
    this.conditions = value
    return this
  }

  /**
   * @returns {Join}
   */
  resetConditions () {
    return this.setConditions([])
  }

  /**
   * @returns {Array}
   */
  getConditions () {
    return this.conditions
  }
}

@@ -327,16 +327,37 @@
  = type%0A
+    this.wheres = %5B%5D%0A
     this
@@ -397,33 +397,8 @@
 ble%0A
-    this.conditions = %5B%5D%0A
   %7D%0A
@@ -975,25 +975,21 @@
 ns(this.
-condition
+where
 s.slice(
@@ -2253,25 +2253,21 @@
 rn this.
-condition
+where
 s.length
@@ -2370,25 +2370,21 @@
    this.
-condition
+where
 s = valu
@@ -2576,17 +2576,13 @@
 his.
-condition
+where
 s%0A  

Update join expression