diff --git a/src/QueryBuilderParser/JoinSupportingQueryBuilderParser.php b/src/QueryBuilderParser/JoinSupportingQueryBuilderParser.php index 9d15d36..4664d77 100644 --- a/src/QueryBuilderParser/JoinSupportingQueryBuilderParser.php +++ b/src/QueryBuilderParser/JoinSupportingQueryBuilderParser.php @@ -95,28 +95,51 @@ private function buildSubclauseQuery($query, $rule, $value, $condition) $not = array_key_exists('not_exists', $subclause) && $subclause['not_exists']; - // Create a where exists clause to join to the other table, and find results matching the criteria - $query = $query->whereExists( - /** - * @param Builder $query - */ - function(Builder $query) use ($subclause) { - - $q = $query->selectRaw(1) - ->from($subclause['to_table']) - ->whereRaw($subclause['to_table'].'.'.$subclause['to_col'] - .' = ' - .$subclause['from_table'].'.'.$subclause['from_col']); - - if (array_key_exists('to_clause', $subclause)) { - $q->where($subclause['to_clause']); - } - - $this->buildSubclauseInnerQuery($subclause, $q); - }, - $condition, - $not - ); + if ( $not ) { + // Create a where exists clause to join to the other table, and find results matching the criteria + $query = $query->whereExists( + /** + * @param Builder $query + */ + function(Builder $query) use ($subclause, $not, $condition) { + $q = $query->selectRaw(1) + ->from($subclause['to_table']) + ->whereRaw($subclause['to_table'].'.'.$subclause['to_col'] + .' = ' + .$subclause['from_table'].'.'.$subclause['from_col']); + if ( ! isset( $subclause["through"] ) ) { + if ( array_key_exists( 'to_clause', $subclause ) ) { + $q->where( $subclause['to_clause'] ); + } + $this->buildSubclauseInnerQuery( $subclause, $q ); + } else { + $this->buildSubclauseThroughQuery( $subclause, $not, $condition, $q ); + } + + }, + $condition, + $not + ); + } else { + // Create a join clause to join to the other table, and find results matching the criteria + + $query = $query->join( $subclause["to_table"], $subclause['to_table'] . '.' . $subclause['to_col'], '=', $subclause['from_table'] . '.' . $subclause['from_col'] ); + $first_from_col = $subclause['from_col']; + $first_from = $subclause['from_table']; + //Loop through the 'through' key to access through multiple tables + while ( isset( $subclause['through'] ) ) { + $subclause["through"]["require_array"] = $subclause["require_array"]; + $subclause["through"]["operator"] = $subclause["operator"]; + $subclause["through"]["value"] = $subclause["value"]; + $subclause = $subclause["through"]; + $query = $query->join( $subclause["to_table"], $subclause['to_table'] . '.' . $subclause['to_col'], '=', $subclause['from_table'] . '.' . $subclause['from_col'] ); + } + if (array_key_exists('to_clause', $subclause)) { + $query->where($subclause['to_clause']); + } + $this->buildSubclauseInnerQuery( $subclause, $query ); + $query->groupBy( $first_from.".".$first_from_col ); + } return $query; } @@ -206,4 +229,36 @@ private function buildSubclauseWithNull($subclause, Builder $query, $isNotNull = return $query->whereNull($subclause['to_value_column']); } + private function buildSubclauseThroughQuery($subclause, $not, $condition, Builder $q) { + $subclause["through"]["require_array"] = $subclause["require_array"]; + $subclause["through"]["operator"] = $subclause["operator"]; + $subclause["through"]["value"] = $subclause["value"]; + $subclause = $subclause["through"]; + + $q->whereExists( + function ( \Illuminate\Database\Query\Builder $query ) use ( $subclause, $not, $condition, $q ) { + + $q = $query->selectRaw( 1 ) + ->from( $subclause['to_table'] ) + ->whereRaw( $subclause['to_table'] . '.' . $subclause['to_col'] + . ' = ' + . $subclause['from_table'] . '.' . $subclause['from_col'] ); + + + + if ( ! isset( $subclause["through"] ) ) { + if ( array_key_exists( 'to_clause', $subclause ) ) { + $q->where( $subclause['to_clause'] ); + } + $this->buildSubclauseInnerQuery( $subclause, $q ); + } else { + $this->buildSubclauseThroughQuery( $subclause, $not, $condition, $q ); + } + }, + $condition, + $not + ); + return $q; + } + } diff --git a/tests/JoinSupportingQueryBuilderParserTest.php b/tests/JoinSupportingQueryBuilderParserTest.php index 6acfd77..a23d0cd 100644 --- a/tests/JoinSupportingQueryBuilderParserTest.php +++ b/tests/JoinSupportingQueryBuilderParserTest.php @@ -37,6 +37,21 @@ private function getJoinFields() 'to_value_column' => 's_value', 'to_clause' => array('othercol' => 'value'), ), + 'join2through' => array( + 'from_table' => 'master2', + 'from_col' => 'm2_col', + 'to_table' => 'subtable2', + 'to_col' => 's2_col', + 'to_value_column' => 's2_value', + 'not_exists' => true, + 'through' => array( + 'from_table' => 'subtable2', + 'from_col' => 's2_col', + 'to_table' => 'subtable3', + 'to_col' => 's3_col', + 'to_value_column' => 's3_value', + ) + ), ); } @@ -328,4 +343,17 @@ public function testDateNotBetween() $this->assertEquals(22, $bindings[0]->day); $this->assertEquals(28, $bindings[1]->day); } + + public function testJoinNotExistsInThrough() + { + $json = '{"condition":"AND","rules":[{"id":"join2through","field":"join2through","type":"text","input":"select","operator":"in","value":["a","b"]}]}'; + + $builder = $this->createQueryBuilder(); + + $parser = $this->getParserUnderTest(); + $parser->parse($json, $builder); + + $this->assertEquals('select * where not exists (select 1 from `subtable2` where subtable2.s2_col = master2.m2_col and not exists (select 1 from `subtable3` where subtable3.s3_col = subtable2.s2_col and `s3_value` in (?, ?)))', + $builder->toSql()); + } }