Skip to content

Commit 37af6ef

Browse files
authored
Merge pull request #1 from na2axl/adding_link_query
The link() extension is functionnal for the select() query.
2 parents 315a265 + 3ff5835 commit 37af6ef

File tree

4 files changed

+171
-43
lines changed

4 files changed

+171
-43
lines changed

src/JSONDB/Benchmark.php

Lines changed: 27 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,8 @@ class Benchmark {
5959
* @return void
6060
*/
6161
public function mark( $name ) {
62-
self::$marker[$name] = microtime( ) ;
62+
self::$marker[$name]['e'] = microtime( ) ;
63+
self::$marker[$name]['m'] = memory_get_usage( ) ;
6364
}
6465

6566
/**
@@ -73,24 +74,41 @@ public function elapsed_time( $point1 = '', $point2 = '', $decimals = 4 ) {
7374
if ( $point1 === '' ) {
7475
return '{elapsed_time}' ;
7576
}
76-
if ( !array_key_exists( $point1, self::$marker )) {
77+
if ( !array_key_exists( $point1, self::$marker ) ) {
7778
return '' ;
7879
}
79-
if ( !array_key_exists( $point2, self::$marker )) {
80-
self::$marker[$point2] = microtime( ) ;
80+
if ( !array_key_exists( $point2, self::$marker ) ) {
81+
self::$marker[$point2]['e'] = microtime( ) ;
82+
self::$marker[$point2]['m'] = memory_get_usage( ) ;
8183
}
82-
list( $sm, $ss ) = explode( ' ', self::$marker[$point1] ) ;
83-
list( $em, $es ) = explode( ' ', self::$marker[$point2] ) ;
84+
list( $sm, $ss ) = explode( ' ', self::$marker[$point1]['e'] ) ;
85+
list( $em, $es ) = explode( ' ', self::$marker[$point2]['e'] ) ;
8486

8587
return number_format( ( $em + $es ) - ( $sm + $ss ), $decimals ) ;
8688
}
8789

8890
/**
8991
* Calculate the memory usage of a benchmark point
90-
* @return int
92+
* @param string $point1 The name of the first benchmark point
93+
* @param string $point2 The name of the second benchmark point
94+
* @param int $decimals
95+
* @return mixed
9196
*/
92-
public function memory_usage( ) {
93-
return memory_get_usage();
97+
public function memory_usage( $point1 = '', $point2 = '', $decimals = 4 ) {
98+
if ( $point1 === '' ) {
99+
return '{memory_usage}' ;
100+
}
101+
if ( !array_key_exists( $point1, self::$marker ) ) {
102+
return '' ;
103+
}
104+
if ( !array_key_exists( $point2, self::$marker ) ) {
105+
self::$marker[$point2]['e'] = microtime( ) ;
106+
self::$marker[$point2]['m'] = memory_get_usage( ) ;
107+
}
108+
$sm = self::$marker[$point1]['m'] ;
109+
$em = self::$marker[$point2]['m'] ;
110+
111+
return number_format( $em - $sm , $decimals ) ;
94112
}
95113

96114
}

src/JSONDB/JSONDB.php

Lines changed: 69 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -303,7 +303,7 @@ public function createServer($path, $username, $password, $connect = FALSE)
303303
fclose($htaccess);
304304

305305
$htpasswd = fopen(realpath(dirname(__DIR__) . '/config/.htpasswd'), 'a+');
306-
fwrite($htpasswd, $username . ':' . crypt($password) . "\n");
306+
fwrite($htpasswd, $username . ':' . crypt($password, NULL) . "\n");
307307
fclose($htpasswd);
308308

309309
$this->config->addUser(realpath($path), $username, $password);
@@ -428,7 +428,7 @@ public function createTable($name, array $prototype)
428428
}
429429

430430
$fields = array();
431-
$properties = array('last_insert_id' => 0, 'last_valid_row_id' => 0, 'primary_keys' => array(), 'unique_keys' => array());
431+
$properties = array('last_insert_id' => 0, 'last_valid_row_id' => 0, 'last_link_id' => 0, 'primary_keys' => array(), 'unique_keys' => array());
432432
$ai_exist = FALSE;
433433
foreach ($prototype as $field => $prop) {
434434
$has_ai = array_key_exists('auto_increment', $prop);
@@ -666,9 +666,9 @@ protected function _parseValue($value, $properties)
666666
$link_table_path = $this->_getTablePath($link_info[0]);
667667
$link_table_data = $this->getTableData($link_table_path);
668668
$value = $this->_parseValue($value, $link_table_data['properties'][$link_info[1]]);
669-
foreach ((array)$link_table_data['data'] as $data) {
669+
foreach ((array)$link_table_data['data'] as $linkID => $data) {
670670
if ($data[$link_info[1]] === $value) {
671-
return $data['#rowid'];
671+
return $linkID;
672672
}
673673
}
674674
throw new Exception("JSONDB Error: There is no value \"{$value}\" in any rows of the table \"{$link_info[0]}\" at the column \"{$link_info[1]}\".");
@@ -728,6 +728,8 @@ protected function _parseValue($value, $properties)
728728
protected function _select($data)
729729
{
730730
$result = $data['data'];
731+
$field_links = array();
732+
$column_links = array();
731733

732734
foreach ((array)$this->parsedQuery['extensions'] as $name => $parameters) {
733735
switch ($name) {
@@ -755,14 +757,58 @@ protected function _select($data)
755757
case 'limit':
756758
$result = array_slice($result, $parameters[0], $parameters[1]);
757759
break;
760+
761+
case 'on':
762+
if (count($parameters) > 0) {
763+
foreach ((array)$parameters as $field) {
764+
$field_links[] = $field;
765+
}
766+
}
767+
break;
768+
769+
case 'link':
770+
if (count($parameters) > 0) {
771+
foreach ((array)$parameters as $field) {
772+
$column_links[] = $field;
773+
}
774+
}
775+
break;
776+
}
777+
}
778+
779+
if (count($field_links) === count($column_links)) {
780+
$links = array_combine($field_links, $column_links);
781+
} else {
782+
throw new Exception('JSONDB Error: Invalid numbers of links. Given "' . count($field_links) .'" columns to link but receive "' . count($column_links) . '" links');
783+
}
784+
785+
if (count($links) > 0) {
786+
foreach ((array)$result as $index => $result_p) {
787+
foreach ($links as $field => $columns) {
788+
if (preg_match('#link\((.+)\)#', $data['properties'][$field]['type'], $link)) {
789+
$link_info = explode('.', $link[1]);
790+
$link_table_path = $this->_getTablePath($link_info[0]);
791+
$link_table_data = $this->getTableData($link_table_path);
792+
foreach ((array)$link_table_data['data'] as $linkID => $value) {
793+
if ($linkID === $result_p[$field]) {
794+
if (in_array('*', $columns, TRUE)) {
795+
$columns = array_diff($link_table_data['prototype'], array('#rowid'));
796+
}
797+
$result[$index][$field] = array_intersect_key($value, array_flip($columns));
798+
}
799+
}
800+
} else {
801+
throw new Exception("JSONDB Error: Can't link tables with the column \"{$field}\". The column is not of type link.");
802+
}
803+
}
758804
}
759805
}
760806

761807
$temp = array();
762808
if (in_array('last_insert_id', $this->parsedQuery['parameters'], TRUE)) {
763809
$temp['last_insert_id'] = $data['properties']['last_insert_id'];
764810
} elseif (!in_array('*', $this->parsedQuery['parameters'], TRUE)) {
765-
foreach ((array)$result as $line) {
811+
foreach ((array)$result as $linkID => $line) {
766812
$temp[] = array_intersect_key($line, array_flip($this->parsedQuery['parameters']));
767813
}
768814
if (array_key_exists('as', $this->parsedQuery['extensions'])) {
@@ -782,13 +828,12 @@ protected function _select($data)
782828
unset($t);
783829
}
784830
} else {
785-
foreach ((array)$result as $line) {
831+
foreach ((array)$result as $linkID => $line) {
786832
$temp[] = array_diff_key($line, array('#rowid' => '#rowid'));
787833
}
788834
}
789-
$result = $temp;
790835

791-
$this->queryResults = $result;
836+
$this->queryResults = $temp;
792837

793838
return new QueryResult($this->queryResults, $this);
794839
}
@@ -818,9 +863,10 @@ protected function _insert($data)
818863
}
819864
$current_data = $data['data'];
820865
$ai_id = (int)$data['properties']['last_insert_id'];
821-
$insert = array(array('#rowid' => (int)$data['properties']['last_valid_row_id'] + 1));
866+
$lk_id = (int)$data['properties']['last_link_id'] + 1;
867+
$insert = array('#'.$lk_id => array('#rowid' => (int)$data['properties']['last_valid_row_id'] + 1));
822868
foreach ((array)$this->parsedQuery['parameters'] as $key => $value) {
823-
$insert[0][$rows[$key]] = $this->_parseValue($value, $data['properties'][$rows[$key]]);
869+
$insert['#'.$lk_id][$rows[$key]] = $this->_parseValue($value, $data['properties'][$rows[$key]]);
824870
}
825871

826872
if (array_key_exists('and', $this->parsedQuery['extensions'])) {
@@ -833,7 +879,7 @@ protected function _insert($data)
833879
foreach ((array)$values as $key => $value) {
834880
$to_add[$rows[$key]] = $this->_parseValue($value, $data['properties'][$rows[$key]]);
835881
}
836-
$insert[] = $to_add;
882+
$insert['#'.++$lk_id] = $to_add;
837883
}
838884
}
839885

@@ -863,9 +909,10 @@ protected function _insert($data)
863909

864910
$pk_error = FALSE;
865911
$non_pk = array_flip(array_diff($data['prototype'], $data['properties']['primary_keys']));
866-
foreach ($insert as $index => $array_data) {
912+
$i = 0;
913+
foreach ($insert as $array_data) {
867914
$array_data = array_diff_key($array_data, $non_pk);
868-
foreach (array_slice($insert, $index + 1) as $value) {
915+
foreach (array_slice($insert, $i + 1) as $value) {
869916
$value = array_diff_key($value, $non_pk);
870917
$pk_error = $pk_error || ($value === $array_data);
871918
if ($pk_error) {
@@ -874,36 +921,40 @@ protected function _insert($data)
874921
throw new Exception("JSONDB Error: Can't insert value. Duplicate values \"{$values}\" for primary keys \"{$keys}\".");
875922
}
876923
}
924+
$i++;
877925
}
878926

879927
$uk_error = FALSE;
928+
$i = 0;
880929
foreach ((array)$data['properties']['unique_keys'] as $uk) {
881-
foreach ($insert as $index => $array_data) {
930+
foreach ($insert as $array_data) {
882931
$array_data = array_intersect_key($array_data, array($uk => $uk));
883-
foreach (array_slice($insert, $index + 1) as $value) {
932+
foreach (array_slice($insert, $i + 1) as $value) {
884933
$value = array_intersect_key($value, array($uk => $uk));
885934
$uk_error = $uk_error || (!empty($item[$uk]) && ($value === $array_data));
886935
if ($uk_error) {
887936
throw new Exception("JSONDB Error: Can't insert value. Duplicate values \"{$value[$uk]}\" for unique key \"{$uk}\".");
888937
}
889938
}
939+
$i++;
890940
}
891941
}
892942

893-
foreach ($insert as $key => &$line) {
943+
foreach ($insert as &$line) {
894944
uksort($line, function ($after, $now) use ($data) {
895945
return array_search($now, $data['prototype'], TRUE) < array_search($after, $data['prototype'], TRUE);
896946
});
897947
}
898948
unset($line);
899949

900-
usort($insert, function ($after, $now) {
901-
return $now['#rowid'] < $after['#rowid'];
950+
uksort($insert, function ($after, $now) use ($insert) {
951+
return $insert[$now]['#rowid'] < $insert[$after]['#rowid'];
902952
});
903953

904954
$data['data'] = $insert;
905955
$data['properties']['last_valid_row_id'] = $this->_getLastValidRowID($insert, FALSE);
906956
$data['properties']['last_insert_id'] = $ai_id;
957+
$data['properties']['last_link_id'] = $lk_id;
907958

908959
$this->cache->update($this->_getTablePath(), $data);
909960

src/JSONDB/QueryParser.php

Lines changed: 45 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -185,13 +185,27 @@ public function parse($query)
185185
case 'group':
186186
$extensions['group'] = $this->_parseGroupExtension($string);
187187
break;
188+
189+
case 'on':
190+
if (!array_key_exists('on', $extensions)) {
191+
$extensions['on'] = array();
192+
}
193+
$extensions['on'][] = $this->_parseOnExtension($string);
194+
break;
195+
196+
case 'link':
197+
if (!array_key_exists('link', $extensions)) {
198+
$extensions['link'] = array();
199+
}
200+
$extensions['link'][] = $this->_parseLinkExtension($string);
201+
break;
188202
}
189203
}
190204
$this->parsedQuery['extensions'] = $extensions;
191205

192206
$this->parsedQuery['benchmark'] = array(
193207
'elapsed_time' => $benchmark->elapsed_time('jsondb_query_parse_start', 'jsondb_query_parse_end'),
194-
'memory_usage' => $benchmark->memory_usage()
208+
'memory_usage' => $benchmark->memory_usage('jsondb_query_parse_start', 'jsondb_query_parse_end')
195209
);
196210

197211
return $this->parsedQuery;
@@ -379,7 +393,7 @@ private function _parseGroupExtension($clause)
379393
}, explode(',', $clause));
380394
$parsedClause = NULL !== $parsedClause[0] ? $parsedClause : array();
381395
if (count($parsedClause) === 0) {
382-
throw new Exception("JSONDB Query Parse Error: At least one parameter expected for the \"as()\" extension.");
396+
throw new Exception("JSONDB Query Parse Error: At least one parameter expected for the \"group()\" extension.");
383397
}
384398
if (count($parsedClause) > 1) {
385399
throw new Exception("JSONDB Query Parse Error: Too much parameters given to the \"group()\" extension, only one required.");
@@ -388,6 +402,35 @@ private function _parseGroupExtension($clause)
388402
return $parsedClause;
389403
}
390404

405+
private function _parseOnExtension($clause)
406+
{
407+
$parsedClause = array_map(function($field) {
408+
return trim($field, self::TRIM_CHAR);
409+
}, explode(',', $clause));
410+
$parsedClause = NULL !== $parsedClause[0] ? $parsedClause : array();
411+
if (count($parsedClause) === 0) {
412+
throw new Exception("JSONDB Query Parse Error: At least one parameter expected for the \"on()\" extension.");
413+
}
414+
if (count($parsedClause) > 1) {
415+
throw new Exception("JSONDB Query Parse Error: Too much parameters given to the \"on()\" extension, only one required.");
416+
}
417+
418+
return $parsedClause[0];
419+
}
420+
421+
private function _parseLinkExtension($clause)
422+
{
423+
$parsedClause = array_map(function($field) {
424+
return trim($field, self::TRIM_CHAR);
425+
}, explode(',', $clause));
426+
$parsedClause = NULL !== $parsedClause[0] ? $parsedClause : array();
427+
if (count($parsedClause) === 0) {
428+
throw new Exception("JSONDB Query Parse Error: At least one parameter expected for the \"link()\" extension.");
429+
}
430+
431+
return $parsedClause;
432+
}
433+
391434
/**
392435
* Parses a value
393436
*

0 commit comments

Comments
 (0)